#include <cppunit/config/SourcePrefix.h>

#include "PKB.h"
#include "QueryTable.h"
#include "QueryExpressionParser.h"
#include "QueryEvaluator.h"
#include "TestQueryEvaluatorWithPKB.h"

void QueryEvaluatorWithPKBTest::setUp() {
}

void QueryEvaluatorWithPKBTest::tearDown() {
}


void printParentMatrixInQE(Type::Map::ParentMatrix& parentMatrix){
	std::cout<<"\nPARENTMATRIX\n";
	// print line matrix
	Type::Map::ParentMatrix::iterator it;
	for(it = parentMatrix.begin(); it != parentMatrix.end(); it++){
		Type::Map::ParentMap row = it->second;

		if(it == parentMatrix.begin()){
			Type::Map::ParentMap::iterator itFirstRow;
			std::cout<<"\t";
			for(itFirstRow = row.begin(); itFirstRow != row.end(); itFirstRow++){
				std::cout<<itFirstRow->first<<"\t";
			}
			std::cout<<endl;
		}

		std::cout<<it->first<<"\t";

		Type::Map::ParentMap::iterator itRow;
		for(itRow = row.begin(); itRow != row.end(); itRow++){
			std::cout<<itRow->second<<"\t";
		}
		std::cout<<endl;
	}
}

// Registers the fixture into the 'registry'
CPPUNIT_TEST_SUITE_REGISTRATION( QueryEvaluatorWithPKBTest );

// method to test the constructor
void QueryEvaluatorWithPKBTest::testConstructor() {
	// Just to ensure it does not produce errors
	PKB pkb; // PKB needed for query evaluator constructor
	QueryEvaluator evaluator(&pkb);
}

PKB QueryEvaluatorWithPKBTest::setUpPkb() {
	// Sets up a PKB with the following SIMPLE source code:
	// Procedure MyProc {
	//1.	x = 2;
	//2.	y = x;
	//3.	while x {
	//4.		x = x - 1;
	//5.		y = y + x;
	//6.		while y {
	//7.			z = y - 1;
	//			}
	//		}
	//8.	y = 5;
	// }
	PKB pkb;

	Type::Index::Proc procIndex = pkb.insertProc("MyProc");
	pkb.insertProcStartEnd(procIndex, 1, 8);
	Type::Index::Var xIndex = pkb.insertVar("x");
	Type::Index::Var yIndex = pkb.insertVar("y");
	Type::Index::Var zIndex = pkb.insertVar("z");
	//build AST
	TreeNode* progNode = pkb.createTreeNode(AST_PROGRAM);
	TreeNode* procNode = pkb.createTreeNode(AST_PROCEDURE, procIndex);
	TreeNode* procStmtListNode = pkb.createTreeNode(AST_STMTLST);
	TreeNode* assign1Node = pkb.createTreeNode(AST_ASSIGN,1);
	TreeNode* varRef1Node = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* con2Node1 = pkb.createTreeNode(AST_CONST, 2);
	
	TreeNode* assign2Node = pkb.createTreeNode(AST_ASSIGN, 2);
	TreeNode* varRef2Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* varX2Node = pkb.createTreeNode(AST_VAR, xIndex);

	TreeNode* while1Node = pkb.createTreeNode(AST_WHILE, 3);
	TreeNode* varRefWNode = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* whileStmtListNode = pkb.createTreeNode(AST_STMTLST);
	TreeNode* assign3Node = pkb.createTreeNode(AST_ASSIGN,4);
	TreeNode* varRef3Node = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* minus3Node = pkb.createTreeNode(AST_MINUS);
	TreeNode* varX3Node = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* con1Node3 = pkb.createTreeNode(AST_CONST, 1);

	TreeNode* assign4Node = pkb.createTreeNode(AST_ASSIGN,5);
	TreeNode* varRef4Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* plus4Node = pkb.createTreeNode(AST_PLUS);
	TreeNode* varY4Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* varX4Node = pkb.createTreeNode(AST_VAR, xIndex);

	TreeNode* while2Node = pkb.createTreeNode(AST_WHILE, 6);
	TreeNode* varRefW2Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* while2StmtListNode = pkb.createTreeNode(AST_STMTLST);

	TreeNode* assign5Node = pkb.createTreeNode(AST_ASSIGN,7);
	TreeNode* varRef5Node = pkb.createTreeNode(AST_VAR, zIndex);
	TreeNode* minus5Node = pkb.createTreeNode(AST_MINUS);
	TreeNode* varY5Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* con1Node5 = pkb.createTreeNode(AST_CONST, 1);

	TreeNode* assign6Node = pkb.createTreeNode(AST_ASSIGN, 8);
	TreeNode* varRef6Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* con5Node6 = pkb.createTreeNode(AST_CONST, 5);

	//link nodes
	pkb.setRoot(progNode);
	pkb.linkNodes(progNode,procNode);
	pkb.linkNodes(procNode,procStmtListNode);
	pkb.linkNodes(procStmtListNode,assign1Node);
	pkb.linkNodes(procStmtListNode,assign2Node);
	pkb.linkNodes(procStmtListNode,while1Node);
	pkb.linkNodes(procStmtListNode,assign6Node);

	pkb.linkNodes(assign1Node,varRef1Node);
	pkb.linkNodes(assign1Node,con2Node1);
	pkb.linkNodes(assign2Node,varRef2Node);
	pkb.linkNodes(assign2Node,varX2Node);
	pkb.linkNodes(while1Node, varRefWNode);
	pkb.linkNodes(while1Node, whileStmtListNode);
	pkb.linkNodes(whileStmtListNode, assign3Node);
	pkb.linkNodes(whileStmtListNode, assign4Node);
	pkb.linkNodes(whileStmtListNode, while2Node);
	pkb.linkNodes(assign3Node, varRef3Node);
	pkb.linkNodes(assign3Node, minus3Node);
	pkb.linkNodes(minus3Node, varX3Node);
	pkb.linkNodes(minus3Node, con1Node3);
	pkb.linkNodes(assign4Node, varRef4Node);
	pkb.linkNodes(assign4Node, plus4Node);
	pkb.linkNodes(plus4Node, varY4Node);
	pkb.linkNodes(plus4Node, varX4Node);
	
	pkb.linkNodes(while2Node, varRefW2Node);
	pkb.linkNodes(while2Node, while2StmtListNode);
	pkb.linkNodes(while2StmtListNode, assign5Node);
	pkb.linkNodes(assign5Node, varRef5Node);
	pkb.linkNodes(assign5Node, minus5Node);
	pkb.linkNodes(minus5Node, varY5Node);
	pkb.linkNodes(minus5Node, con1Node5);

	pkb.linkNodes(assign6Node, varRef6Node);
	pkb.linkNodes(assign6Node, con5Node6);

	pkb.insertLineEntity(1, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(2, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(3, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(4, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(5, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(6, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(7, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(8, Type::Entity::ASSIGNMENT_LINE_ENTITY);

	pkb.insertNode(1,assign1Node);
	pkb.insertNode(2,assign2Node);
	pkb.insertNode(3,while1Node);
	pkb.insertNode(4,assign3Node);
	pkb.insertNode(5,assign4Node);
	pkb.insertNode(6,while2Node);
	pkb.insertNode(7,assign5Node);
	pkb.insertNode(8,assign6Node);
	
	pkb.insertConstant(1,Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.insertConstant(4,Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(7,Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(8,Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);

	pkb.setProcModifies(1,1);
	pkb.setProcModifies(1,2);
	pkb.setProcModifies(1,3);

	pkb.setLineModifies(1,Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(2,Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(3,Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineModifies(3,Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineModifies(3,Type::Entity::WHILE_LINE_ENTITY, 3);
	pkb.setLineModifies(4,Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(5, Type::Entity::ASSIGNMENT_LINE_ENTITY,2);
	pkb.setLineModifies(6, Type::Entity::WHILE_LINE_ENTITY,3);
	pkb.setLineModifies(7, Type::Entity::ASSIGNMENT_LINE_ENTITY,3);
	pkb.setLineModifies(8, Type::Entity::ASSIGNMENT_LINE_ENTITY,2);

	pkb.setProcUses(1,1);
	pkb.setProcUses(1,2);

	pkb.setLineUses(2,Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(3,Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineUses(4,Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY,1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY,2);
	pkb.setLineUses(6, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineUses(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setFollows(1, 2);
	pkb.setFollows(2, 3);
	pkb.setFollows(3, 8);
	pkb.setFollows(4, 5);
	pkb.setFollows(5, 6);
	pkb.setParent(3, 4);
	pkb.setParent(3, 5);
	pkb.setParent(3, 6);
	pkb.setParent(6, 7);

	return pkb;
}

// Sets up a PKB with the following SIMPLE source code:
// Procedure MyProc {
//1.	x = 2;
//2.	y = x;
//3.	while x {
//4.		x = x - 1;
//5.		y = y + x;
//6.		while y {
//7.			z = y - 1;
//			}
//		}
//8.	y = 5;
//9.	while x {
//10.		while y {
//11.			call YourProc;
//			}
//		}
// }
//
// Procedure YourProc {
//12.	a = 9;
//13.	b = b + c;
//14.	call YourOtherProc;
// }
//
// Procedure YourOtherProc {
//15.	d = d + 15;
//16.	while d {
//17.		d = e;
//		}
// }
PKB QueryEvaluatorWithPKBTest::setUpPkbWithMultipleProcedures() {
	PKB pkb;

	/**-------------------------------------------------------------------
	 * Insert Procedures
	 *
	 *-------------------------------------------------------------------*/
	Type::Index::Proc procIndex1 = pkb.insertProc("MyProc");
	pkb.insertProcStartEnd(procIndex1, 1, 11);
	Type::Index::Proc procIndex2 = pkb.insertProc("YourProc");
	pkb.insertProcStartEnd(procIndex2, 12, 14);
	Type::Index::Proc procIndex3 = pkb.insertProc("YourOtherProc");
	pkb.insertProcStartEnd(procIndex3, 15, 17);

	/**-------------------------------------------------------------------
	 * Insert Variables
	 *
	 *-------------------------------------------------------------------*/
	Type::Index::Var xIndex = pkb.insertVar("x");
	Type::Index::Var yIndex = pkb.insertVar("y");
	Type::Index::Var zIndex = pkb.insertVar("z");
	Type::Index::Var aIndex = pkb.insertVar("a");
	Type::Index::Var bIndex = pkb.insertVar("b");
	Type::Index::Var cIndex = pkb.insertVar("c");
	Type::Index::Var dIndex = pkb.insertVar("d");
	Type::Index::Var eIndex = pkb.insertVar("e");

	/**-------------------------------------------------------------------
	 * Build AST
	 *
	 *-------------------------------------------------------------------*/
	TreeNode* progNode = pkb.createTreeNode(AST_PROGRAM);
	TreeNode* procNode1 = pkb.createTreeNode(AST_PROCEDURE, procIndex1);
	TreeNode* procStmtListNode1 = pkb.createTreeNode(AST_STMTLST);

	// Line 1
	TreeNode* assign1Node = pkb.createTreeNode(AST_ASSIGN,1);
	TreeNode* varRef1Node = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* con2Node1 = pkb.createTreeNode(AST_CONST, 2);
	
	// Line 2
	TreeNode* assign2Node = pkb.createTreeNode(AST_ASSIGN, 2);
	TreeNode* varRef2Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* varX2Node = pkb.createTreeNode(AST_VAR, xIndex);

	// Line 3
	TreeNode* while1Node = pkb.createTreeNode(AST_WHILE, 3);
	TreeNode* varRefWNode = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* while1StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 4
	TreeNode* assign3Node = pkb.createTreeNode(AST_ASSIGN,4);
	TreeNode* varRef3Node = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* minus3Node = pkb.createTreeNode(AST_MINUS);
	TreeNode* varX3Node = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* con1Node3 = pkb.createTreeNode(AST_CONST, 1);

	// Line 5
	TreeNode* assign4Node = pkb.createTreeNode(AST_ASSIGN,5);
	TreeNode* varRef4Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* plus4Node = pkb.createTreeNode(AST_PLUS);
	TreeNode* varY4Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* varX4Node = pkb.createTreeNode(AST_VAR, xIndex);

	// Line 6
	TreeNode* while2Node = pkb.createTreeNode(AST_WHILE, 6);
	TreeNode* varRefW2Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* while2StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 7
	TreeNode* assign5Node = pkb.createTreeNode(AST_ASSIGN,7);
	TreeNode* varRef5Node = pkb.createTreeNode(AST_VAR, zIndex);
	TreeNode* minus5Node = pkb.createTreeNode(AST_MINUS);
	TreeNode* varY5Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* con1Node5 = pkb.createTreeNode(AST_CONST, 1);

	// Line 8
	TreeNode* assign6Node = pkb.createTreeNode(AST_ASSIGN, 8);
	TreeNode* varRef6Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* con5Node6 = pkb.createTreeNode(AST_CONST, 5);

	// Line 9
	TreeNode* while3Node = pkb.createTreeNode(AST_WHILE, 9);
	TreeNode* varRefW3Node = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* while3StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 10
	TreeNode* while4Node = pkb.createTreeNode(AST_WHILE, 10);
	TreeNode* varRefW4Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* while4StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 11
	TreeNode* call1Node = pkb.createTreeNode(AST_CALL, 11);

	// Line 12
	TreeNode* procNode2 = pkb.createTreeNode(AST_PROCEDURE, procIndex2);
	TreeNode* procStmtListNode2 = pkb.createTreeNode(AST_STMTLST);

	TreeNode* assign7Node = pkb.createTreeNode(AST_ASSIGN, 12);
	TreeNode* varRef7Node = pkb.createTreeNode(AST_VAR, aIndex);
	TreeNode* con9Node7 = pkb.createTreeNode(AST_CONST, 9);

	// Line 13
	TreeNode* assign8Node = pkb.createTreeNode(AST_ASSIGN, 13);
	TreeNode* varRef8Node = pkb.createTreeNode(AST_VAR, bIndex);
	TreeNode* plus8Node = pkb.createTreeNode(AST_PLUS);
	TreeNode* varB8Node = pkb.createTreeNode(AST_VAR, bIndex);
	TreeNode* varC8Node = pkb.createTreeNode(AST_VAR, cIndex);

	// Line 14
	TreeNode* call2Node = pkb.createTreeNode(AST_CALL, 14);

	// Line 15
	TreeNode* procNode3 = pkb.createTreeNode(AST_PROCEDURE, procIndex3);
	TreeNode* procStmtListNode3 = pkb.createTreeNode(AST_STMTLST);

	TreeNode* assign9Node = pkb.createTreeNode(AST_ASSIGN, 15);
	TreeNode* varRef9Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* plus9Node = pkb.createTreeNode(AST_PLUS);
	TreeNode* varD9Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* con15Node9 = pkb.createTreeNode(AST_CONST, 15);

	// Line 16
	TreeNode* while5Node = pkb.createTreeNode(AST_WHILE, 16);
	TreeNode* varRefW5Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* while5StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 17
	TreeNode* assign10Node = pkb.createTreeNode(AST_ASSIGN, 17);
	TreeNode* varRef10Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* varE10Node = pkb.createTreeNode(AST_VAR, eIndex);

	/**-------------------------------------------------------------------
	 * Link Nodes
	 *
	 *-------------------------------------------------------------------*/
	pkb.setRoot(progNode);
	pkb.linkNodes(progNode, procNode1);
	pkb.linkNodes(progNode, procNode2);
	pkb.linkNodes(progNode, procNode3);

	// MyProc
	pkb.linkNodes(procNode1, procStmtListNode1);
	pkb.linkNodes(procStmtListNode1, assign1Node);
	pkb.linkNodes(procStmtListNode1, assign2Node);
	pkb.linkNodes(procStmtListNode1, while1Node);
	pkb.linkNodes(procStmtListNode1, assign6Node);
	pkb.linkNodes(procStmtListNode1, while3Node);

	pkb.linkNodes(assign1Node, varRef1Node);
	pkb.linkNodes(assign1Node, con2Node1);
	pkb.linkNodes(assign2Node, varRef2Node);
	pkb.linkNodes(assign2Node, varX2Node);
	pkb.linkNodes(while1Node, varRefWNode);
	pkb.linkNodes(while1Node, while1StmtListNode);
	pkb.linkNodes(while1StmtListNode, assign3Node);
	pkb.linkNodes(while1StmtListNode, assign4Node);
	pkb.linkNodes(while1StmtListNode, while2Node);
	pkb.linkNodes(assign3Node, varRef3Node);
	pkb.linkNodes(assign3Node, minus3Node);
	pkb.linkNodes(minus3Node, varX3Node);
	pkb.linkNodes(minus3Node, con1Node3);
	pkb.linkNodes(assign4Node, varRef4Node);
	pkb.linkNodes(assign4Node, plus4Node);
	pkb.linkNodes(plus4Node, varY4Node);
	pkb.linkNodes(plus4Node, varX4Node);
	
	pkb.linkNodes(while2Node, varRefW2Node);
	pkb.linkNodes(while2Node, while2StmtListNode);
	pkb.linkNodes(while2StmtListNode, assign5Node);
	pkb.linkNodes(assign5Node, varRef5Node);
	pkb.linkNodes(assign5Node, minus5Node);
	pkb.linkNodes(minus5Node, varY5Node);
	pkb.linkNodes(minus5Node, con1Node5);

	pkb.linkNodes(assign6Node, varRef6Node);
	pkb.linkNodes(assign6Node, con5Node6);

	pkb.linkNodes(while3Node, varRefW3Node);
	pkb.linkNodes(while3Node, while3StmtListNode);
	pkb.linkNodes(while3StmtListNode, while4Node);
	pkb.linkNodes(while4Node, varRefW4Node);
	pkb.linkNodes(while4Node, while4StmtListNode);
	pkb.linkNodes(while4StmtListNode, call1Node);

	// YourProc
	pkb.linkNodes(procNode2, procStmtListNode2);
	pkb.linkNodes(procStmtListNode2, assign7Node);
	pkb.linkNodes(procStmtListNode2, assign8Node);
	pkb.linkNodes(procStmtListNode2, call2Node);

	pkb.linkNodes(assign7Node, varRef7Node);
	pkb.linkNodes(assign7Node, con9Node7);
	pkb.linkNodes(assign8Node, varRef8Node);
	pkb.linkNodes(assign8Node, plus8Node);
	pkb.linkNodes(plus8Node, varB8Node);
	pkb.linkNodes(plus8Node, varC8Node);
	
	// YourOtherProc
	pkb.linkNodes(procNode3, procStmtListNode3);
	pkb.linkNodes(procStmtListNode3, assign9Node);
	pkb.linkNodes(procStmtListNode3, while5Node);

	pkb.linkNodes(assign9Node, varRef9Node);
	pkb.linkNodes(assign9Node, plus9Node);
	pkb.linkNodes(plus9Node, varD9Node);
	pkb.linkNodes(plus9Node, con15Node9);

	pkb.linkNodes(while5Node, varRefW5Node);
	pkb.linkNodes(while5Node, while5StmtListNode);
	pkb.linkNodes(while5StmtListNode, assign10Node);
	pkb.linkNodes(assign10Node, varRef10Node);
	pkb.linkNodes(assign10Node, varE10Node);

	/**-------------------------------------------------------------------
	 * Insert indexes into PKB
	 *
	 *-------------------------------------------------------------------*/
	pkb.insertLineEntity(1, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(2, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(3, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(4, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(5, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(6, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(7, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(8, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(9, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(10,Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(11, Type::Entity::CALL_LINE_ENTITY);
	pkb.insertLineEntity(12, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(13, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(14, Type::Entity::CALL_LINE_ENTITY);
	pkb.insertLineEntity(15, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(16, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(17, Type::Entity::ASSIGNMENT_LINE_ENTITY);

	pkb.insertNode(1,assign1Node);
	pkb.insertNode(2,assign2Node);
	pkb.insertNode(3,while1Node);
	pkb.insertNode(4,assign3Node);
	pkb.insertNode(5,assign4Node);
	pkb.insertNode(6,while2Node);
	pkb.insertNode(7,assign5Node);
	pkb.insertNode(8,assign6Node);
	pkb.insertNode(9,while3Node);
	pkb.insertNode(10,while4Node);
	pkb.insertNode(11,call1Node);
	pkb.insertNode(12,assign7Node);
	pkb.insertNode(13,assign8Node);
	pkb.insertNode(14,call2Node);
	pkb.insertNode(15,assign9Node);
	pkb.insertNode(16,while5Node);
	pkb.insertNode(17,assign10Node);

	pkb.insertConstant(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.insertConstant(4, Type::Entity::ASSIGNMENT_LINE_ENTITY,1);
	pkb.insertConstant(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(8, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.insertConstant(12, Type::Entity::ASSIGNMENT_LINE_ENTITY, 9);
	pkb.insertConstant(15, Type::Entity::ASSIGNMENT_LINE_ENTITY, 15);

	/**-------------------------------------------------------------------
	 * Set Relationships
	 *
	 *-------------------------------------------------------------------*/
	pkb.setProcModifies(1,1);
	pkb.setProcModifies(1,2);
	pkb.setProcModifies(1,3);
	pkb.setProcModifies(1,4);
	pkb.setProcModifies(1,5);
	pkb.setProcModifies(1,7);
	pkb.setProcModifies(2,4);
	pkb.setProcModifies(2,5);
	pkb.setProcModifies(2,7);
	pkb.setProcModifies(3,7);

	pkb.setLineModifies(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 3);
	pkb.setLineModifies(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(6, Type::Entity::WHILE_LINE_ENTITY, 3);
	pkb.setLineModifies(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 3);
	pkb.setLineModifies(8, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(9, Type::Entity::WHILE_LINE_ENTITY, 4);
	pkb.setLineModifies(9, Type::Entity::WHILE_LINE_ENTITY, 5);
	pkb.setLineModifies(9, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineModifies(10, Type::Entity::WHILE_LINE_ENTITY, 4);
	pkb.setLineModifies(10, Type::Entity::WHILE_LINE_ENTITY, 5);
	pkb.setLineModifies(10, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineModifies(11, Type::Entity::CALL_LINE_ENTITY, 4);
	pkb.setLineModifies(11, Type::Entity::CALL_LINE_ENTITY, 5);
	pkb.setLineModifies(11, Type::Entity::CALL_LINE_ENTITY, 7);
	pkb.setLineModifies(12, Type::Entity::ASSIGNMENT_LINE_ENTITY, 4);
	pkb.setLineModifies(13, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.setLineModifies(14, Type::Entity::CALL_LINE_ENTITY, 7);
	pkb.setLineModifies(15, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);
	pkb.setLineModifies(16, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineModifies(17, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);

	pkb.setProcUses(1,1);
	pkb.setProcUses(1,2);
	pkb.setProcUses(1,5);
	pkb.setProcUses(1,6);
	pkb.setProcUses(1,7);
	pkb.setProcUses(1,8);
	pkb.setProcUses(2,5);
	pkb.setProcUses(2,6);
	pkb.setProcUses(2,7);
	pkb.setProcUses(2,8);
	pkb.setProcUses(3,7);
	pkb.setProcUses(3,8);

	pkb.setLineUses(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(3, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineUses(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(6, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineUses(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(9, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineUses(9, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineUses(9, Type::Entity::WHILE_LINE_ENTITY, 5);
	pkb.setLineUses(9, Type::Entity::WHILE_LINE_ENTITY, 6);
	pkb.setLineUses(9, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineUses(9, Type::Entity::WHILE_LINE_ENTITY, 8);
	pkb.setLineUses(10, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineUses(10, Type::Entity::WHILE_LINE_ENTITY, 5);
	pkb.setLineUses(10, Type::Entity::WHILE_LINE_ENTITY, 6);
	pkb.setLineUses(10, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineUses(10, Type::Entity::WHILE_LINE_ENTITY, 8);
	pkb.setLineUses(11, Type::Entity::CALL_LINE_ENTITY, 5);
	pkb.setLineUses(11, Type::Entity::CALL_LINE_ENTITY, 6);
	pkb.setLineUses(11, Type::Entity::CALL_LINE_ENTITY, 7);
	pkb.setLineUses(11, Type::Entity::CALL_LINE_ENTITY, 8);
	pkb.setLineUses(13, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.setLineUses(13, Type::Entity::ASSIGNMENT_LINE_ENTITY, 6);
	pkb.setLineUses(14, Type::Entity::CALL_LINE_ENTITY, 7);
	pkb.setLineUses(14, Type::Entity::CALL_LINE_ENTITY, 8);
	pkb.setLineUses(15, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);
	pkb.setLineUses(16, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineUses(16, Type::Entity::WHILE_LINE_ENTITY, 8);
	pkb.setLineUses(17, Type::Entity::ASSIGNMENT_LINE_ENTITY, 8);

	pkb.setFollows(1, 2);
	pkb.setFollows(2, 3);
	pkb.setFollows(3, 8);
	pkb.setFollows(4, 5);
	pkb.setFollows(5, 6);
	pkb.setFollows(8, 9);
	pkb.setFollows(12, 13);
	pkb.setFollows(13, 14);
	pkb.setFollows(15, 16);

	pkb.setParent(3, 4);
	pkb.setParent(3, 5);
	pkb.setParent(3, 6);
	pkb.setParent(6, 7);
	pkb.setParent(9, 10);
	pkb.setParent(10, 11); 
	pkb.setParent(16, 17);

	pkb.setCalls(1, 11, 2);
	pkb.setCalls(2, 14, 3);

	pkb.setNext(1, 2);
	pkb.setNext(2, 3);
	pkb.setNext(3, 4);
	pkb.setNext(3, 8);
	pkb.setNext(4, 5);
	pkb.setNext(5, 6);
	pkb.setNext(6, 7);
	pkb.setNext(6, 3);
	pkb.setNext(7, 6);
	pkb.setNext(8, 9);
	pkb.setNext(9, 10);
	pkb.setNext(10, 11);
	pkb.setNext(10, 9);
	pkb.setNext(11, 10);
	pkb.setNext(12, 13);
	pkb.setNext(13, 14);
	pkb.setNext(15, 16);
	pkb.setNext(16, 17);
	pkb.setNext(17, 16);
	
	/**------------------------------------------------------
	 * SET BIT MAPS
	 *
	 *--------------------------------------------------------*/
	std::vector<int> procsList = pkb.getProcIndices();
	unsigned int numProcs = procsList.size();
	std::vector<int> linesList = pkb.getLines();
	unsigned int numLines = linesList.size();
	std::vector<int> varsList = pkb.getVarIndices();
	unsigned int numVars = varsList.size();
	
	// Initialize the rows to be used for the bitmaps
	// + 1 because index 0 is not used (for simplicity in the bitmaps)
	std::vector<bool> booleanProcRow(numProcs + 1, false);
	std::vector<bool> booleanLineRow(numLines + 1, false);
	std::vector<bool> booleanVarRow(numVars + 1, false);

	// Inititalize the bit maps to all false
	// + 1 because index 0 is not used (for simplicity in the bitmaps)
	Type::Map::Bit bitMapCalls(numProcs + 1, booleanProcRow);
	Type::Map::Bit bitMapLineModifies(numLines + 1, booleanVarRow);
	Type::Map::Bit bitMapLineUses(numLines + 1, booleanVarRow);
	Type::Map::Bit bitMapProcModifies(numProcs + 1, booleanVarRow);
	Type::Map::Bit bitMapProcUses(numProcs + 1, booleanVarRow);
	
	// Set the CALLS bit map
	// Proc 1
	booleanProcRow = std::vector<bool>(numProcs + 1, false);
	booleanProcRow.at(2) = true; // Calls(1,2)
	bitMapCalls.at(1) = booleanProcRow;
	// Proc 2
	booleanProcRow = std::vector<bool>(numProcs + 1, false);
	booleanProcRow.at(3) = true; // Calls(2,3)
	bitMapCalls.at(2) = booleanProcRow;

	pkb.setCallsBitMap(bitMapCalls);

	// Set the LINEMODIFIES bit map
	// Line 1
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Modifies(1,1)
	bitMapLineModifies.at(1) = booleanVarRow;
	// Line 2
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(2) = true; // Modifies(2,2)
	bitMapLineModifies.at(2) = booleanVarRow;
	// Line 3
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Modifies(3,1)
	booleanVarRow.at(2) = true; // Modifies(3,2)
	booleanVarRow.at(3) = true; // Modifies(3,3)
	bitMapLineModifies.at(3) = booleanVarRow;
	// Line 4
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Modifies(4,1)
	bitMapLineModifies.at(4) = booleanVarRow;
	// Line 5
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(2) = true; // Modifies(5,2)
	bitMapLineModifies.at(5) = booleanVarRow;
	// Line 6
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(3) = true; // Modifies(6,3)
	bitMapLineModifies.at(6) = booleanVarRow;
	// Line 7
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(3) = true; // Modifies(7,3)
	bitMapLineModifies.at(7) = booleanVarRow;
	// Line 8
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(2) = true; // Modifies(8,2)
	bitMapLineModifies.at(8) = booleanVarRow;
	// Line 9
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(4) = true; // Modifies(9,4)
	booleanVarRow.at(5) = true; // Modifies(9,5)
	booleanVarRow.at(7) = true; // Modifies(9,7)
	bitMapLineModifies.at(9) = booleanVarRow;
	// Line 10
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(4) = true; // Modifies(10,4)
	booleanVarRow.at(5) = true; // Modifies(10,5)
	booleanVarRow.at(7) = true; // Modifies(10,7)
	bitMapLineModifies.at(10) = booleanVarRow;
	// Line 11
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(4) = true; // Modifies(11,4)
	booleanVarRow.at(5) = true; // Modifies(11,5)
	booleanVarRow.at(7) = true; // Modifies(11,7)
	bitMapLineModifies.at(11) = booleanVarRow;
	// Line 12
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(4) = true; // Modifies(12,4)
	bitMapLineModifies.at(12) = booleanVarRow;
	// Line 13
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(5) = true; // Modifies(13,5)
	bitMapLineModifies.at(13) = booleanVarRow;
	// Line 14
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(14,7)
	bitMapLineModifies.at(14) = booleanVarRow;
	// Line 15
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(15,7)
	bitMapLineModifies.at(15) = booleanVarRow;
	// Line 16
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(16,7)
	bitMapLineModifies.at(16) = booleanVarRow;
	// Line 17
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(17,7)
	bitMapLineModifies.at(17) = booleanVarRow;

	pkb.setLineModifiesBitMap(bitMapLineModifies);

	// Set the LINEUSES bit map
	// Line 2
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Uses(2,1)
	bitMapLineUses.at(2) = booleanVarRow;
	// Line 3
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Uses(3,1)
	booleanVarRow.at(2) = true; // Uses(3,2)
	bitMapLineUses.at(3) = booleanVarRow;
	// Line 4
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Uses(4,1)
	bitMapLineUses.at(4) = booleanVarRow;
	// Line 5
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Uses(5,1)
	booleanVarRow.at(2) = true; // Uses(5,2)
	bitMapLineUses.at(5) = booleanVarRow;
	// Line 6
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(2) = true; // Uses(6,2)
	bitMapLineUses.at(6) = booleanVarRow;
	// Line 7
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(2) = true; // Uses(7,2)
	bitMapLineUses.at(7) = booleanVarRow;
	// Line 9
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Uses(9,1)
	booleanVarRow.at(2) = true; // Uses(9,2)
	booleanVarRow.at(5) = true; // Uses(9,5)
	booleanVarRow.at(6) = true; // Uses(9,6)
	booleanVarRow.at(7) = true; // Uses(9,7)
	booleanVarRow.at(8) = true; // Uses(9,8)
	bitMapLineUses.at(9) = booleanVarRow;
	// Line 10
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(2) = true; // Uses(10,2)
	booleanVarRow.at(5) = true; // Uses(10,5)
	booleanVarRow.at(6) = true; // Uses(10,6)
	booleanVarRow.at(7) = true; // Uses(10,7)
	booleanVarRow.at(8) = true; // Uses(10,8)
	bitMapLineUses.at(10) = booleanVarRow;
	// Line 11
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(5) = true; // Uses(11,5)
	booleanVarRow.at(6) = true; // Uses(11,6)
	booleanVarRow.at(7) = true; // Uses(11,7)
	booleanVarRow.at(8) = true; // Uses(11,8)
	bitMapLineUses.at(11) = booleanVarRow;
	// Line 13
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(5) = true; // Uses(13,5)
	booleanVarRow.at(6) = true; // Uses(13,6)
	bitMapLineUses.at(13) = booleanVarRow;
	// Line 14
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(14,7)
	booleanVarRow.at(8) = true; // Uses(14,8)
	bitMapLineUses.at(14) = booleanVarRow;
	// Line 15
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(15,7)
	bitMapLineUses.at(15) = booleanVarRow;
	// Line 16
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(16,7)
	booleanVarRow.at(8) = true; // Uses(16,8)
	bitMapLineUses.at(16) = booleanVarRow;
	// Line 17
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(8) = true; // Uses(17,8)
	bitMapLineUses.at(17) = booleanVarRow;

	pkb.setLineUsesBitMap(bitMapLineUses);

	// Set the PROCMODIFIES bit map
	// Proc 1
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Modifies(1,1)
	booleanVarRow.at(2) = true; // Modifies(1,2)
	booleanVarRow.at(3) = true; // Modifies(1,3)
	booleanVarRow.at(4) = true; // Modifies(1,4)
	booleanVarRow.at(5) = true; // Modifies(1,5)
	booleanVarRow.at(7) = true; // Modifies(1,7)
	bitMapProcModifies.at(1) = booleanVarRow;
	// Proc 2
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(4) = true; // Modifies(2,4)
	booleanVarRow.at(5) = true; // Modifies(2,5)
	booleanVarRow.at(7) = true; // Modifies(2,7)
	bitMapProcModifies.at(2) = booleanVarRow;
	// Proc 3
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(3,7)
	bitMapProcModifies.at(3) = booleanVarRow;

	pkb.setProcModifiesBitMap(bitMapProcModifies);

	// Set the PROCUSES bit map
	// Proc 1
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Uses(1,1)
	booleanVarRow.at(2) = true; // Uses(1,2)
	booleanVarRow.at(5) = true; // Uses(1,5)
	booleanVarRow.at(6) = true; // Uses(1,6)
	booleanVarRow.at(7) = true; // Uses(1,7)
	booleanVarRow.at(8) = true; // Uses(1,8)
	bitMapProcUses.at(1) = booleanVarRow;
	// Proc 2
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(5) = true; // Uses(2,5)
	booleanVarRow.at(6) = true; // Uses(2,6)
	booleanVarRow.at(7) = true; // Uses(2,7)
	booleanVarRow.at(8) = true; // Uses(2,8)
	bitMapProcUses.at(2) = booleanVarRow;
	// Proc 3
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(3,7)
	booleanVarRow.at(8) = true; // Uses(3,8)
	bitMapProcUses.at(3) = booleanVarRow;

	pkb.setProcUsesBitMap(bitMapProcUses);
	
// Procedure MyProc {
//1.	x = 2;
//2.	y = x;
//3.	while x {
//4.		x = x - 1;
//5.		y = y + x;
//6.		while y {
//7.			z = y - 1;
//			}
//		}
//8.	y = 5;
//9.	while x {
//10.		while y {
//11.			call YourProc;
//			}
//		}
// }
//
// Procedure YourProc {
//12.	a = 9;
//13.	b = b + c;
//14.	call YourOtherProc;
// }
//
// Procedure YourOtherProc {
//15.	d = d + 15;
//16.	while d {
//17.		d = e;
//		}
// }
	return pkb;
}

// Sets up a PKB with the following SIMPLE source code:
// Procedure MyProc {
//1.	x = 2;
//2.	y = x;
//3.	while x {
//4.		x = x - 1;
//5.		y = y + x;
//6.		while y {
//7.			z = y - 1;
//			}
//		}
//8.	y = 5;
//9.	while x {
//10.		while y {
//11.			call YourProc;
//			}
//		}
// }
//
// Procedure YourProc {
//12.	a = 9;
//13.	b = b + c;
//14.	call YourOtherProc;
// }
//
// Procedure YourOtherProc {
//15.	d = d + 15;
//16.	while d {
//17.		d = e;
//		}
// }
//
// Procedure IfStmtProc {
//18.	if d then {
//19.		d = e;
//20.		while d {
//21.			d = e - 1 * 2;
//			}
//		} else {
//22.		d = e;
//23.		while d {
//24.			d = e - 1 * 2;
//			}
//		}
//25.	while d {
//26.		if d then {
//27.			d = e;
//28.			while d {
//29.				d = e - 1 * 2;
//				}
//			} else {
//30.			d = e;
//31.			while d {
//32.				d = e - 1 * 2;
//				}
//			}
//		}
//	}
PKB QueryEvaluatorWithPKBTest::setUpPkbWithMultipleProceduresAndIfStmts() {
	PKB pkb;

	/**-------------------------------------------------------------------
	 * Insert Procedures
	 *
	 *-------------------------------------------------------------------*/
	Type::Index::Proc procIndex1 = pkb.insertProc("MyProc");
	pkb.insertProcStartEnd(procIndex1, 1, 11);
	Type::Index::Proc procIndex2 = pkb.insertProc("YourProc");
	pkb.insertProcStartEnd(procIndex2, 12, 14);
	Type::Index::Proc procIndex3 = pkb.insertProc("YourOtherProc");
	pkb.insertProcStartEnd(procIndex3, 15, 17);
	Type::Index::Proc procIndex4 = pkb.insertProc("IfStmtProc");
	pkb.insertProcStartEnd(procIndex4, 18, 32);

	/**-------------------------------------------------------------------
	 * Insert Variables
	 *
	 *-------------------------------------------------------------------*/
	Type::Index::Var xIndex = pkb.insertVar("x"); // 1
	Type::Index::Var yIndex = pkb.insertVar("y"); // 2
	Type::Index::Var zIndex = pkb.insertVar("z"); // 3
	Type::Index::Var aIndex = pkb.insertVar("a"); // 4
	Type::Index::Var bIndex = pkb.insertVar("b"); // 5
	Type::Index::Var cIndex = pkb.insertVar("c"); // 6
	Type::Index::Var dIndex = pkb.insertVar("d"); // 7
	Type::Index::Var eIndex = pkb.insertVar("e"); // 8

	/**-------------------------------------------------------------------
	 * Build AST
	 *
	 *-------------------------------------------------------------------*/
	TreeNode* progNode = pkb.createTreeNode(AST_PROGRAM);
	TreeNode* procNode1 = pkb.createTreeNode(AST_PROCEDURE, procIndex1);
	TreeNode* procStmtListNode1 = pkb.createTreeNode(AST_STMTLST);

	// Line 1
	TreeNode* assign1Node = pkb.createTreeNode(AST_ASSIGN,1);
	TreeNode* varRef1Node = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* con2Node1 = pkb.createTreeNode(AST_CONST, 2);
	
	// Line 2
	TreeNode* assign2Node = pkb.createTreeNode(AST_ASSIGN, 2);
	TreeNode* varRef2Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* varX2Node = pkb.createTreeNode(AST_VAR, xIndex);

	// Line 3
	TreeNode* while1Node = pkb.createTreeNode(AST_WHILE, 3);
	TreeNode* varRefWNode = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* while1StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 4
	TreeNode* assign3Node = pkb.createTreeNode(AST_ASSIGN,4);
	TreeNode* varRef3Node = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* minus3Node = pkb.createTreeNode(AST_MINUS);
	TreeNode* varX3Node = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* con1Node3 = pkb.createTreeNode(AST_CONST, 1);

	// Line 5
	TreeNode* assign4Node = pkb.createTreeNode(AST_ASSIGN,5);
	TreeNode* varRef4Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* plus4Node = pkb.createTreeNode(AST_PLUS);
	TreeNode* varY4Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* varX4Node = pkb.createTreeNode(AST_VAR, xIndex);

	// Line 6
	TreeNode* while2Node = pkb.createTreeNode(AST_WHILE, 6);
	TreeNode* varRefW2Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* while2StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 7
	TreeNode* assign5Node = pkb.createTreeNode(AST_ASSIGN,7);
	TreeNode* varRef5Node = pkb.createTreeNode(AST_VAR, zIndex);
	TreeNode* minus5Node = pkb.createTreeNode(AST_MINUS);
	TreeNode* varY5Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* con1Node5 = pkb.createTreeNode(AST_CONST, 1);

	// Line 8
	TreeNode* assign6Node = pkb.createTreeNode(AST_ASSIGN, 8);
	TreeNode* varRef6Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* con5Node6 = pkb.createTreeNode(AST_CONST, 5);

	// Line 9
	TreeNode* while3Node = pkb.createTreeNode(AST_WHILE, 9);
	TreeNode* varRefW3Node = pkb.createTreeNode(AST_VAR, xIndex);
	TreeNode* while3StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 10
	TreeNode* while4Node = pkb.createTreeNode(AST_WHILE, 10);
	TreeNode* varRefW4Node = pkb.createTreeNode(AST_VAR, yIndex);
	TreeNode* while4StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 11
	TreeNode* call1Node = pkb.createTreeNode(AST_CALL, 11);

	// Line 12
	TreeNode* procNode2 = pkb.createTreeNode(AST_PROCEDURE, procIndex2);
	TreeNode* procStmtListNode2 = pkb.createTreeNode(AST_STMTLST);

	TreeNode* assign7Node = pkb.createTreeNode(AST_ASSIGN, 12);
	TreeNode* varRef7Node = pkb.createTreeNode(AST_VAR, aIndex);
	TreeNode* con9Node7 = pkb.createTreeNode(AST_CONST, 9);

	// Line 13
	TreeNode* assign8Node = pkb.createTreeNode(AST_ASSIGN, 13);
	TreeNode* varRef8Node = pkb.createTreeNode(AST_VAR, bIndex);
	TreeNode* plus8Node = pkb.createTreeNode(AST_PLUS);
	TreeNode* varB8Node = pkb.createTreeNode(AST_VAR, bIndex);
	TreeNode* varC8Node = pkb.createTreeNode(AST_VAR, cIndex);

	// Line 14
	TreeNode* call2Node = pkb.createTreeNode(AST_CALL, 14);

	// Line 15
	TreeNode* procNode3 = pkb.createTreeNode(AST_PROCEDURE, procIndex3);
	TreeNode* procStmtListNode3 = pkb.createTreeNode(AST_STMTLST);

	TreeNode* assign9Node = pkb.createTreeNode(AST_ASSIGN, 15);
	TreeNode* varRef9Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* plus9Node = pkb.createTreeNode(AST_PLUS);
	TreeNode* varD9Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* con15Node9 = pkb.createTreeNode(AST_CONST, 15);

	// Line 16
	TreeNode* while5Node = pkb.createTreeNode(AST_WHILE, 16);
	TreeNode* varRefW5Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* while5StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 17
	TreeNode* assign10Node = pkb.createTreeNode(AST_ASSIGN, 17);
	TreeNode* varRef10Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* varE10Node = pkb.createTreeNode(AST_VAR, eIndex);

	// Line 18
	TreeNode* procNode4 = pkb.createTreeNode(AST_PROCEDURE, procIndex4);
	TreeNode* procStmtListNode4 = pkb.createTreeNode(AST_STMTLST);

	TreeNode* if1Node = pkb.createTreeNode(AST_IF, 18);
	TreeNode* if1VarNode = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* if1ThenNode = pkb.createTreeNode(AST_STMTLST);
	TreeNode* if1ElseNode = pkb.createTreeNode(AST_STMTLST);

	// Line 19
	TreeNode* assign11Node = pkb.createTreeNode(AST_ASSIGN, 19);
	TreeNode* varRef11Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* varE11Node = pkb.createTreeNode(AST_VAR, eIndex);

	// Line 20
	TreeNode* while6Node = pkb.createTreeNode(AST_WHILE, 20);
	TreeNode* varRefW6Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* while6StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 21
	TreeNode* assign12Node = pkb.createTreeNode(AST_ASSIGN, 21);
	TreeNode* varRef12Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* varE12Node = pkb.createTreeNode(AST_VAR, eIndex);
	TreeNode* minus12Node = pkb.createTreeNode(AST_MINUS);
	TreeNode* con1Node12 = pkb.createTreeNode(AST_CONST, 1);
	TreeNode* times12Node = pkb.createTreeNode(AST_TIMES);
	TreeNode* con2Node12 = pkb.createTreeNode(AST_CONST, 2);

	// Line 22
	TreeNode* assign13Node = pkb.createTreeNode(AST_ASSIGN, 22);
	TreeNode* varRef13Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* varE13Node = pkb.createTreeNode(AST_VAR, eIndex);

	// Line 23
	TreeNode* while7Node = pkb.createTreeNode(AST_WHILE, 23);
	TreeNode* varRefW7Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* while7StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 24
	TreeNode* assign14Node = pkb.createTreeNode(AST_ASSIGN, 24);
	TreeNode* varRef14Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* varE14Node = pkb.createTreeNode(AST_VAR, eIndex);
	TreeNode* minus14Node = pkb.createTreeNode(AST_MINUS);
	TreeNode* con1Node14 = pkb.createTreeNode(AST_CONST, 1);
	TreeNode* times14Node = pkb.createTreeNode(AST_TIMES);
	TreeNode* con2Node14 = pkb.createTreeNode(AST_CONST, 2);

	// Line 25
	TreeNode* while8Node = pkb.createTreeNode(AST_WHILE, 25);
	TreeNode* varRefW8Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* while8StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 26
	TreeNode* if2Node = pkb.createTreeNode(AST_IF, 26);
	TreeNode* if2VarNode = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* if2ThenNode = pkb.createTreeNode(AST_STMTLST);
	TreeNode* if2ElseNode = pkb.createTreeNode(AST_STMTLST);

	// Line 27
	TreeNode* assign15Node = pkb.createTreeNode(AST_ASSIGN, 27);
	TreeNode* varRef15Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* varE15Node = pkb.createTreeNode(AST_VAR, eIndex);

	// Line 28
	TreeNode* while9Node = pkb.createTreeNode(AST_WHILE, 28);
	TreeNode* varRefW9Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* while9StmtListNode = pkb.createTreeNode(AST_STMTLST);

	// Line 29
	TreeNode* assign16Node = pkb.createTreeNode(AST_ASSIGN, 29);
	TreeNode* varRef16Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* varE16Node = pkb.createTreeNode(AST_VAR, eIndex);
	TreeNode* minus16Node = pkb.createTreeNode(AST_MINUS);
	TreeNode* con1Node16 = pkb.createTreeNode(AST_CONST, 1);
	TreeNode* times16Node = pkb.createTreeNode(AST_TIMES);
	TreeNode* con2Node16 = pkb.createTreeNode(AST_CONST, 2);

	// Line 30
	TreeNode* assign17Node = pkb.createTreeNode(AST_ASSIGN, 30);
	TreeNode* varRef17Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* varE17Node = pkb.createTreeNode(AST_VAR, eIndex);

	// Line 31
	TreeNode* while10Node = pkb.createTreeNode(AST_WHILE, 31);
	TreeNode* varRefW10Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* while10StmtListNode = pkb.createTreeNode(AST_STMTLST);
	
	// Line 32
	TreeNode* assign18Node = pkb.createTreeNode(AST_ASSIGN, 32);
	TreeNode* varRef18Node = pkb.createTreeNode(AST_VAR, dIndex);
	TreeNode* varE18Node = pkb.createTreeNode(AST_VAR, eIndex);
	TreeNode* minus18Node = pkb.createTreeNode(AST_MINUS);
	TreeNode* con1Node18 = pkb.createTreeNode(AST_CONST, 1);
	TreeNode* times18Node = pkb.createTreeNode(AST_TIMES);
	TreeNode* con2Node18 = pkb.createTreeNode(AST_CONST, 2);

	/**-------------------------------------------------------------------
	 * Link Nodes
	 *
	 *-------------------------------------------------------------------*/
	pkb.setRoot(progNode);
	pkb.linkNodes(progNode, procNode1);
	pkb.linkNodes(progNode, procNode2);
	pkb.linkNodes(progNode, procNode3);
	pkb.linkNodes(progNode, procNode4);

	// MyProc
	pkb.linkNodes(procNode1, procStmtListNode1);
	pkb.linkNodes(procStmtListNode1, assign1Node);
	pkb.linkNodes(procStmtListNode1, assign2Node);
	pkb.linkNodes(procStmtListNode1, while1Node);
	pkb.linkNodes(procStmtListNode1, assign6Node);
	pkb.linkNodes(procStmtListNode1, while3Node);

	pkb.linkNodes(assign1Node, varRef1Node);
	pkb.linkNodes(assign1Node, con2Node1);
	pkb.linkNodes(assign2Node, varRef2Node);
	pkb.linkNodes(assign2Node, varX2Node);
	pkb.linkNodes(while1Node, varRefWNode);
	pkb.linkNodes(while1Node, while1StmtListNode);
	pkb.linkNodes(while1StmtListNode, assign3Node);
	pkb.linkNodes(while1StmtListNode, assign4Node);
	pkb.linkNodes(while1StmtListNode, while2Node);
	pkb.linkNodes(assign3Node, varRef3Node);
	pkb.linkNodes(assign3Node, minus3Node);
	pkb.linkNodes(minus3Node, varX3Node);
	pkb.linkNodes(minus3Node, con1Node3);
	pkb.linkNodes(assign4Node, varRef4Node);
	pkb.linkNodes(assign4Node, plus4Node);
	pkb.linkNodes(plus4Node, varY4Node);
	pkb.linkNodes(plus4Node, varX4Node);
	
	pkb.linkNodes(while2Node, varRefW2Node);
	pkb.linkNodes(while2Node, while2StmtListNode);
	pkb.linkNodes(while2StmtListNode, assign5Node);
	pkb.linkNodes(assign5Node, varRef5Node);
	pkb.linkNodes(assign5Node, minus5Node);
	pkb.linkNodes(minus5Node, varY5Node);
	pkb.linkNodes(minus5Node, con1Node5);

	pkb.linkNodes(assign6Node, varRef6Node);
	pkb.linkNodes(assign6Node, con5Node6);

	pkb.linkNodes(while3Node, varRefW3Node);
	pkb.linkNodes(while3Node, while3StmtListNode);
	pkb.linkNodes(while3StmtListNode, while4Node);
	pkb.linkNodes(while4Node, varRefW4Node);
	pkb.linkNodes(while4Node, while4StmtListNode);
	pkb.linkNodes(while4StmtListNode, call1Node);

	// YourProc
	pkb.linkNodes(procNode2, procStmtListNode2);
	pkb.linkNodes(procStmtListNode2, assign7Node);
	pkb.linkNodes(procStmtListNode2, assign8Node);
	pkb.linkNodes(procStmtListNode2, call2Node);

	pkb.linkNodes(assign7Node, varRef7Node);
	pkb.linkNodes(assign7Node, con9Node7);
	pkb.linkNodes(assign8Node, varRef8Node);
	pkb.linkNodes(assign8Node, plus8Node);
	pkb.linkNodes(plus8Node, varB8Node);
	pkb.linkNodes(plus8Node, varC8Node);
	
	// YourOtherProc
	pkb.linkNodes(procNode3, procStmtListNode3);
	pkb.linkNodes(procStmtListNode3, assign9Node);
	pkb.linkNodes(procStmtListNode3, while5Node);

	pkb.linkNodes(assign9Node, varRef9Node);
	pkb.linkNodes(assign9Node, plus9Node);
	pkb.linkNodes(plus9Node, varD9Node);
	pkb.linkNodes(plus9Node, con15Node9);

	pkb.linkNodes(while5Node, varRefW5Node);
	pkb.linkNodes(while5Node, while5StmtListNode);
	pkb.linkNodes(while5StmtListNode, assign10Node);
	pkb.linkNodes(assign10Node, varRef10Node);
	pkb.linkNodes(assign10Node, varE10Node);

	// IfStmtProc
	pkb.linkNodes(procNode4, procStmtListNode4);
	pkb.linkNodes(procStmtListNode4, if1Node);
	pkb.linkNodes(procStmtListNode4, while8Node);

	pkb.linkNodes(if1Node, if1VarNode);
	pkb.linkNodes(if1Node, if1ThenNode);
	pkb.linkNodes(if1Node, if1ElseNode);

	pkb.linkNodes(if1ThenNode, assign11Node);
	pkb.linkNodes(if1ThenNode, while6Node);

	pkb.linkNodes(while6Node, varRefW6Node);
	pkb.linkNodes(while6Node, while6StmtListNode);
	pkb.linkNodes(while6StmtListNode, assign12Node);

	// AST for d = e - 1 * 2 
	pkb.linkNodes(assign12Node, varRef12Node);
	pkb.linkNodes(assign12Node, minus12Node);
	pkb.linkNodes(minus12Node, varE12Node);
	pkb.linkNodes(minus12Node, times12Node);
	pkb.linkNodes(times12Node, con1Node12);
	pkb.linkNodes(times12Node, con2Node12);

	pkb.linkNodes(if1ElseNode, assign12Node);
	pkb.linkNodes(if1ElseNode, while7Node);

	pkb.linkNodes(while7Node, varRefW7Node);
	pkb.linkNodes(while7Node, while7StmtListNode);
	pkb.linkNodes(while7StmtListNode, assign14Node);

	// AST for d = e - 1 * 2 
	pkb.linkNodes(assign14Node, varRef14Node);
	pkb.linkNodes(assign14Node, minus14Node);
	pkb.linkNodes(minus14Node, varE14Node);
	pkb.linkNodes(minus14Node, times14Node);
	pkb.linkNodes(times14Node, con1Node14);
	pkb.linkNodes(times14Node, con2Node14);

	pkb.linkNodes(while8Node, varRefW8Node);
	pkb.linkNodes(while8Node, while8StmtListNode);
	pkb.linkNodes(while8StmtListNode, if2Node);

	pkb.linkNodes(if2Node, if2VarNode);
	pkb.linkNodes(if2Node, if2ThenNode);
	pkb.linkNodes(if2Node, if2ElseNode);

	pkb.linkNodes(if2ThenNode, assign15Node);
	pkb.linkNodes(if2ThenNode, while9Node);

	pkb.linkNodes(while9Node, varRefW9Node);
	pkb.linkNodes(while9Node, while9StmtListNode);
	pkb.linkNodes(while9StmtListNode, assign16Node);

	// AST for d = e - 1 * 2 
	pkb.linkNodes(assign16Node, varRef16Node);
	pkb.linkNodes(assign16Node, minus16Node);
	pkb.linkNodes(minus16Node, varE16Node);
	pkb.linkNodes(minus16Node, times16Node);
	pkb.linkNodes(times16Node, con1Node16);
	pkb.linkNodes(times16Node, con2Node16);

	pkb.linkNodes(if2ElseNode, assign17Node);
	pkb.linkNodes(if2ElseNode, while10Node);

	pkb.linkNodes(while10Node, varRefW10Node);
	pkb.linkNodes(while10Node, while10StmtListNode);
	pkb.linkNodes(while10StmtListNode, assign18Node);

	// AST for d = e - 1 * 2 
	pkb.linkNodes(assign18Node, varRef18Node);
	pkb.linkNodes(assign18Node, minus18Node);
	pkb.linkNodes(minus18Node, varE18Node);
	pkb.linkNodes(minus18Node, times18Node);
	pkb.linkNodes(times18Node, con1Node18);
	pkb.linkNodes(times18Node, con2Node18);

	/**-------------------------------------------------------------------
	 * Insert indexes into PKB
	 *
	 *-------------------------------------------------------------------*/
	pkb.insertLineEntity(1, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(2, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(3, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(4, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(5, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(6, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(7, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(8, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(9, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(10, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(11, Type::Entity::CALL_LINE_ENTITY);
	pkb.insertLineEntity(12, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(13, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(14, Type::Entity::CALL_LINE_ENTITY);
	pkb.insertLineEntity(15, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(16, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(17, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(18, Type::Entity::IF_LINE_ENTITY);
	pkb.insertLineEntity(19, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(20, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(21, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(22, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(23, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(24, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(25, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(26, Type::Entity::IF_LINE_ENTITY);
	pkb.insertLineEntity(27, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(28, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(29, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(30, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(31, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(32, Type::Entity::ASSIGNMENT_LINE_ENTITY);

	pkb.insertNode(1,assign1Node);
	pkb.insertNode(2,assign2Node);
	pkb.insertNode(3,while1Node);
	pkb.insertNode(4,assign3Node);
	pkb.insertNode(5,assign4Node);
	pkb.insertNode(6,while2Node);
	pkb.insertNode(7,assign5Node);
	pkb.insertNode(8,assign6Node);
	pkb.insertNode(9,while3Node);
	pkb.insertNode(10,while4Node);
	pkb.insertNode(11,call1Node);
	pkb.insertNode(12,assign7Node);
	pkb.insertNode(13,assign8Node);
	pkb.insertNode(14,call2Node);
	pkb.insertNode(15,assign9Node);
	pkb.insertNode(16,while5Node);
	pkb.insertNode(17,assign10Node);
	pkb.insertNode(18,if1Node);
	pkb.insertNode(19, assign11Node);
	pkb.insertNode(20, while6Node);
	pkb.insertNode(21, assign12Node);
	pkb.insertNode(22, assign13Node);
	pkb.insertNode(23, while7Node);
	pkb.insertNode(24, assign14Node);
	pkb.insertNode(25, while8Node);
	pkb.insertNode(26, if2Node);
	pkb.insertNode(27, assign15Node);
	pkb.insertNode(28, while9Node);
	pkb.insertNode(29, assign16Node);
	pkb.insertNode(30, assign17Node);
	pkb.insertNode(31, while10Node);
	pkb.insertNode(32, assign18Node);

	pkb.insertConstant(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.insertConstant(4, Type::Entity::ASSIGNMENT_LINE_ENTITY,1);
	pkb.insertConstant(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(8, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.insertConstant(12, Type::Entity::ASSIGNMENT_LINE_ENTITY, 9);
	pkb.insertConstant(15, Type::Entity::ASSIGNMENT_LINE_ENTITY, 15);
	pkb.insertConstant(21, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(21, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.insertConstant(24, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(24, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.insertConstant(29, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(29, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.insertConstant(32, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(32, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);

	/**-------------------------------------------------------------------
	 * Set Relationships
	 *
	 *-------------------------------------------------------------------*/
	pkb.setProcModifies(1,1);
	pkb.setProcModifies(1,2);
	pkb.setProcModifies(1,3);
	pkb.setProcModifies(1,4);
	pkb.setProcModifies(1,5);
	pkb.setProcModifies(1,7);
	pkb.setProcModifies(2,4);
	pkb.setProcModifies(2,5);
	pkb.setProcModifies(2,7);
	pkb.setProcModifies(3,7);
	pkb.setProcModifies(4,7);

	pkb.setLineModifies(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 3);
	pkb.setLineModifies(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(6, Type::Entity::WHILE_LINE_ENTITY, 3);
	pkb.setLineModifies(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 3);
	pkb.setLineModifies(8, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(9, Type::Entity::WHILE_LINE_ENTITY, 4);
	pkb.setLineModifies(9, Type::Entity::WHILE_LINE_ENTITY, 5);
	pkb.setLineModifies(9, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineModifies(10, Type::Entity::WHILE_LINE_ENTITY, 4);
	pkb.setLineModifies(10, Type::Entity::WHILE_LINE_ENTITY, 5);
	pkb.setLineModifies(10, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineModifies(11, Type::Entity::CALL_LINE_ENTITY, 4);
	pkb.setLineModifies(11, Type::Entity::CALL_LINE_ENTITY, 5);
	pkb.setLineModifies(11, Type::Entity::CALL_LINE_ENTITY, 7);
	pkb.setLineModifies(12, Type::Entity::ASSIGNMENT_LINE_ENTITY, 4);
	pkb.setLineModifies(13, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.setLineModifies(14, Type::Entity::CALL_LINE_ENTITY, 7);
	pkb.setLineModifies(15, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);
	pkb.setLineModifies(16, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineModifies(17, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);
	pkb.setLineModifies(18, Type::Entity::IF_LINE_ENTITY, 7);
	pkb.setLineModifies(19, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);
	pkb.setLineModifies(20, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineModifies(21, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);
	pkb.setLineModifies(22, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);
	pkb.setLineModifies(23, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineModifies(24, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);
	pkb.setLineModifies(25, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineModifies(26, Type::Entity::IF_LINE_ENTITY, 7);
	pkb.setLineModifies(27, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);
	pkb.setLineModifies(28, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineModifies(29, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);
	pkb.setLineModifies(30, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);
	pkb.setLineModifies(31, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineModifies(32, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);

	pkb.setProcUses(1,1);
	pkb.setProcUses(1,2);
	pkb.setProcUses(1,5);
	pkb.setProcUses(1,6);
	pkb.setProcUses(1,7);
	pkb.setProcUses(1,8);
	pkb.setProcUses(2,5);
	pkb.setProcUses(2,6);
	pkb.setProcUses(2,7);
	pkb.setProcUses(2,8);
	pkb.setProcUses(3,7);
	pkb.setProcUses(3,8);
	pkb.setProcUses(4,7);
	pkb.setProcUses(4,8);

	pkb.setLineUses(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(3, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineUses(3, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineUses(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(6, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineUses(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(9, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineUses(9, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineUses(9, Type::Entity::WHILE_LINE_ENTITY, 5);
	pkb.setLineUses(9, Type::Entity::WHILE_LINE_ENTITY, 6);
	pkb.setLineUses(9, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineUses(9, Type::Entity::WHILE_LINE_ENTITY, 8);
	pkb.setLineUses(10, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineUses(10, Type::Entity::WHILE_LINE_ENTITY, 5);
	pkb.setLineUses(10, Type::Entity::WHILE_LINE_ENTITY, 6);
	pkb.setLineUses(10, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineUses(10, Type::Entity::WHILE_LINE_ENTITY, 8);
	pkb.setLineUses(11, Type::Entity::CALL_LINE_ENTITY, 5);
	pkb.setLineUses(11, Type::Entity::CALL_LINE_ENTITY, 6);
	pkb.setLineUses(11, Type::Entity::CALL_LINE_ENTITY, 7);
	pkb.setLineUses(11, Type::Entity::CALL_LINE_ENTITY, 8);
	pkb.setLineUses(13, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.setLineUses(13, Type::Entity::ASSIGNMENT_LINE_ENTITY, 6);
	pkb.setLineUses(14, Type::Entity::CALL_LINE_ENTITY, 7);
	pkb.setLineUses(14, Type::Entity::CALL_LINE_ENTITY, 8);
	pkb.setLineUses(15, Type::Entity::ASSIGNMENT_LINE_ENTITY, 7);
	pkb.setLineUses(16, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineUses(16, Type::Entity::WHILE_LINE_ENTITY, 8);
	pkb.setLineUses(17, Type::Entity::ASSIGNMENT_LINE_ENTITY, 8);
	pkb.setLineUses(18, Type::Entity::IF_LINE_ENTITY, 7);
	pkb.setLineUses(18, Type::Entity::IF_LINE_ENTITY, 8);
	pkb.setLineUses(19, Type::Entity::ASSIGNMENT_LINE_ENTITY, 8);
	pkb.setLineUses(20, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineUses(20, Type::Entity::WHILE_LINE_ENTITY, 8);
	pkb.setLineUses(21, Type::Entity::ASSIGNMENT_LINE_ENTITY, 8);
	pkb.setLineUses(22, Type::Entity::ASSIGNMENT_LINE_ENTITY, 8);
	pkb.setLineUses(23, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineUses(23, Type::Entity::WHILE_LINE_ENTITY, 8);
	pkb.setLineUses(24, Type::Entity::ASSIGNMENT_LINE_ENTITY, 8);
	pkb.setLineUses(25, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineUses(25, Type::Entity::WHILE_LINE_ENTITY, 8);
	pkb.setLineUses(26, Type::Entity::IF_LINE_ENTITY, 7);
	pkb.setLineUses(26, Type::Entity::IF_LINE_ENTITY, 8);
	pkb.setLineUses(27, Type::Entity::ASSIGNMENT_LINE_ENTITY, 8);
	pkb.setLineUses(28, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineUses(28, Type::Entity::WHILE_LINE_ENTITY, 8);
	pkb.setLineUses(29, Type::Entity::ASSIGNMENT_LINE_ENTITY, 8);
	pkb.setLineUses(30, Type::Entity::ASSIGNMENT_LINE_ENTITY, 8);
	pkb.setLineUses(31, Type::Entity::WHILE_LINE_ENTITY, 7);
	pkb.setLineUses(31, Type::Entity::WHILE_LINE_ENTITY, 8);
	pkb.setLineUses(32, Type::Entity::ASSIGNMENT_LINE_ENTITY, 8);

	pkb.setFollows(1, 2);
	pkb.setFollows(2, 3);
	pkb.setFollows(3, 8);
	pkb.setFollows(4, 5);
	pkb.setFollows(5, 6);
	pkb.setFollows(8, 9);
	pkb.setFollows(12, 13);
	pkb.setFollows(13, 14);
	pkb.setFollows(15, 16);
	pkb.setFollows(18, 25);
	pkb.setFollows(19, 20);
	pkb.setFollows(22, 23);
	pkb.setFollows(27, 28);
	pkb.setFollows(30, 31);

	pkb.setParent(3, 4);
	pkb.setParent(3, 5);
	pkb.setParent(3, 6);
	pkb.setParent(6, 7);
	pkb.setParent(9, 10);
	pkb.setParent(10, 11); 
	pkb.setParent(16, 17);
	pkb.setParent(18, 19);
	pkb.setParent(18, 20);
	pkb.setParent(20, 21);
	pkb.setParent(18, 22);
	pkb.setParent(18, 23);
	pkb.setParent(23, 24);
	pkb.setParent(25, 26);
	pkb.setParent(26, 27);
	pkb.setParent(26, 28);
	pkb.setParent(28, 29);
	pkb.setParent(26, 30);
	pkb.setParent(26, 31);
	pkb.setParent(31, 32);

	pkb.setCalls(1, 11, 2);
	pkb.setCalls(2, 14, 3);
	
	pkb.setNext(1, 2);
	pkb.setNext(2, 3);
	pkb.setNext(3, 4);
	pkb.setNext(3, 8);
	pkb.setNext(4, 5);
	pkb.setNext(5, 6);
	pkb.setNext(6, 7);
	pkb.setNext(6, 3);
	pkb.setNext(7, 6);
	pkb.setNext(8, 9);
	pkb.setNext(9, 10);
	pkb.setNext(10, 11);
	pkb.setNext(10, 9);
	pkb.setNext(11, 10);
	pkb.setNext(12, 13);
	pkb.setNext(13, 14);
	pkb.setNext(15, 16);
	pkb.setNext(16, 17);
	pkb.setNext(17, 16);
	pkb.setNext(18, 19);
	pkb.setNext(18, 22);
	pkb.setNext(19, 20);
	pkb.setNext(20, 21);
	pkb.setNext(20, 25);
	pkb.setNext(21, 20);
	pkb.setNext(22, 23);
	pkb.setNext(23, 24);
	pkb.setNext(23, 25);
	pkb.setNext(24, 23);
	pkb.setNext(25, 26);
	pkb.setNext(26, 27);
	pkb.setNext(26, 30);
	pkb.setNext(27, 28);
	pkb.setNext(28, 29);
	pkb.setNext(28, 25);
	pkb.setNext(29, 28);
	pkb.setNext(30, 31);
	pkb.setNext(31, 32);
	pkb.setNext(31, 25);
	pkb.setNext(32, 31);

	/**------------------------------------------------------
	 * SET BIT MAPS
	 *
	 *--------------------------------------------------------*/
	std::vector<int> procsList = pkb.getProcIndices();
	unsigned int numProcs = procsList.size();
	std::vector<int> linesList = pkb.getLines();
	unsigned int numLines = linesList.size();
	std::vector<int> varsList = pkb.getVarIndices();
	unsigned int numVars = varsList.size();
	
	// Initialize the rows to be used for the bitmaps
	// + 1 because index 0 is not used (for simplicity in the bitmaps)
	std::vector<bool> booleanProcRow(numProcs + 1, false);
	std::vector<bool> booleanLineRow(numLines + 1, false);
	std::vector<bool> booleanVarRow(numVars + 1, false);

	// Inititalize the bit maps to all false
	// + 1 because index 0 is not used (for simplicity in the bitmaps)
	Type::Map::Bit bitMapCalls(numProcs + 1, booleanProcRow);
	Type::Map::Bit bitMapLineModifies(numLines + 1, booleanVarRow);
	Type::Map::Bit bitMapLineUses(numLines + 1, booleanVarRow);
	Type::Map::Bit bitMapProcModifies(numProcs + 1, booleanVarRow);
	Type::Map::Bit bitMapProcUses(numProcs + 1, booleanVarRow);
	
	// Set the CALLS bit map
	// Proc 1
	booleanProcRow = std::vector<bool>(numProcs + 1, false);
	booleanProcRow.at(2) = true; // Calls(1,2)
	bitMapCalls.at(1) = booleanProcRow;
	// Proc 2
	booleanProcRow = std::vector<bool>(numProcs + 1, false);
	booleanProcRow.at(3) = true; // Calls(2,3)
	bitMapCalls.at(2) = booleanProcRow;

	pkb.setCallsBitMap(bitMapCalls);

	// Set the LINEMODIFIES bit map
	// Line 1
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Modifies(1,1)
	bitMapLineModifies.at(1) = booleanVarRow;
	// Line 2
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(2) = true; // Modifies(2,2)
	bitMapLineModifies.at(2) = booleanVarRow;
	// Line 3
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Modifies(3,1)
	booleanVarRow.at(2) = true; // Modifies(3,2)
	booleanVarRow.at(3) = true; // Modifies(3,3)
	bitMapLineModifies.at(3) = booleanVarRow;
	// Line 4
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Modifies(4,1)
	bitMapLineModifies.at(4) = booleanVarRow;
	// Line 5
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(2) = true; // Modifies(5,2)
	bitMapLineModifies.at(5) = booleanVarRow;
	// Line 6
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(3) = true; // Modifies(6,3)
	bitMapLineModifies.at(6) = booleanVarRow;
	// Line 7
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(3) = true; // Modifies(7,3)
	bitMapLineModifies.at(7) = booleanVarRow;
	// Line 8
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(2) = true; // Modifies(8,2)
	bitMapLineModifies.at(8) = booleanVarRow;
	// Line 9
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(4) = true; // Modifies(9,4)
	booleanVarRow.at(5) = true; // Modifies(9,5)
	booleanVarRow.at(7) = true; // Modifies(9,7)
	bitMapLineModifies.at(9) = booleanVarRow;
	// Line 10
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(4) = true; // Modifies(10,4)
	booleanVarRow.at(5) = true; // Modifies(10,5)
	booleanVarRow.at(7) = true; // Modifies(10,7)
	bitMapLineModifies.at(10) = booleanVarRow;
	// Line 11
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(4) = true; // Modifies(11,4)
	booleanVarRow.at(5) = true; // Modifies(11,5)
	booleanVarRow.at(7) = true; // Modifies(11,7)
	bitMapLineModifies.at(11) = booleanVarRow;
	// Line 12
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(4) = true; // Modifies(12,4)
	bitMapLineModifies.at(12) = booleanVarRow;
	// Line 13
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(5) = true; // Modifies(13,5)
	bitMapLineModifies.at(13) = booleanVarRow;
	// Line 14
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(14,7)
	bitMapLineModifies.at(14) = booleanVarRow;
	// Line 15
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(15,7)
	bitMapLineModifies.at(15) = booleanVarRow;
	// Line 16
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(16,7)
	bitMapLineModifies.at(16) = booleanVarRow;
	// Line 17
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(17,7)
	bitMapLineModifies.at(17) = booleanVarRow;
	// Line 18
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(18,7)
	bitMapLineModifies.at(18) = booleanVarRow;
	// Line 19
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(19,7)
	bitMapLineModifies.at(19) = booleanVarRow;
	// Line 20
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(20,7)
	bitMapLineModifies.at(20) = booleanVarRow;
	// Line 21
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(21,7)
	bitMapLineModifies.at(21) = booleanVarRow;
	// Line 22
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(22,7)
	bitMapLineModifies.at(22) = booleanVarRow;
	// Line 23
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(23,7)
	bitMapLineModifies.at(23) = booleanVarRow;
	// Line 24
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(24,7)
	bitMapLineModifies.at(24) = booleanVarRow;
	// Line 25
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(25,7)
	bitMapLineModifies.at(25) = booleanVarRow;
	// Line 26
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(26,7)
	bitMapLineModifies.at(26) = booleanVarRow;
	// Line 27
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(27,7)
	bitMapLineModifies.at(27) = booleanVarRow;
	// Line 28
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(28,7)
	bitMapLineModifies.at(28) = booleanVarRow;
	// Line 29
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(29,7)
	bitMapLineModifies.at(29) = booleanVarRow;
	// Line 30
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(30,7)
	bitMapLineModifies.at(30) = booleanVarRow;
	// Line 31
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(31,7)
	bitMapLineModifies.at(31) = booleanVarRow;
	// Line 32
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(32,7)
	bitMapLineModifies.at(32) = booleanVarRow;

	pkb.setLineModifiesBitMap(bitMapLineModifies);

	// Set the LINEUSES bit map
	// Line 2
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Uses(2,1)
	bitMapLineUses.at(2) = booleanVarRow;
	// Line 3
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Uses(3,1)
	booleanVarRow.at(2) = true; // Uses(3,2)
	bitMapLineUses.at(3) = booleanVarRow;
	// Line 4
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Uses(4,1)
	bitMapLineUses.at(4) = booleanVarRow;
	// Line 5
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Uses(5,1)
	booleanVarRow.at(2) = true; // Uses(5,2)
	bitMapLineUses.at(5) = booleanVarRow;
	// Line 6
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(2) = true; // Uses(6,2)
	bitMapLineUses.at(6) = booleanVarRow;
	// Line 7
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(2) = true; // Uses(7,2)
	bitMapLineUses.at(7) = booleanVarRow;
	// Line 9
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Uses(9,1)
	booleanVarRow.at(2) = true; // Uses(9,2)
	booleanVarRow.at(5) = true; // Uses(9,5)
	booleanVarRow.at(6) = true; // Uses(9,6)
	booleanVarRow.at(7) = true; // Uses(9,7)
	booleanVarRow.at(8) = true; // Uses(9,8)
	bitMapLineUses.at(9) = booleanVarRow;
	// Line 10
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(2) = true; // Uses(10,2)
	booleanVarRow.at(5) = true; // Uses(10,5)
	booleanVarRow.at(6) = true; // Uses(10,6)
	booleanVarRow.at(7) = true; // Uses(10,7)
	booleanVarRow.at(8) = true; // Uses(10,8)
	bitMapLineUses.at(10) = booleanVarRow;
	// Line 11
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(5) = true; // Uses(11,5)
	booleanVarRow.at(6) = true; // Uses(11,6)
	booleanVarRow.at(7) = true; // Uses(11,7)
	booleanVarRow.at(8) = true; // Uses(11,8)
	bitMapLineUses.at(11) = booleanVarRow;
	// Line 13
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(5) = true; // Uses(13,5)
	booleanVarRow.at(6) = true; // Uses(13,6)
	bitMapLineUses.at(13) = booleanVarRow;
	// Line 14
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(14,7)
	booleanVarRow.at(8) = true; // Uses(14,8)
	bitMapLineUses.at(14) = booleanVarRow;
	// Line 15
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(15,7)
	bitMapLineUses.at(15) = booleanVarRow;
	// Line 16
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(16,7)
	booleanVarRow.at(8) = true; // Uses(16,8)
	bitMapLineUses.at(16) = booleanVarRow;
	// Line 17
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(8) = true; // Uses(17,8)
	bitMapLineUses.at(17) = booleanVarRow;
	// Line 18
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(18,7)
	booleanVarRow.at(8) = true; // Uses(18,8)
	bitMapLineUses.at(18) = booleanVarRow;
	// Line 19
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(8) = true; // Uses(19,8)
	bitMapLineUses.at(19) = booleanVarRow;
	// Line 20
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(20,7)
	booleanVarRow.at(8) = true; // Uses(20,8)
	bitMapLineUses.at(20) = booleanVarRow;
	// Line 21
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(8) = true; // Uses(21,8)
	bitMapLineUses.at(21) = booleanVarRow;
	// Line 22
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(8) = true; // Uses(22,8)
	bitMapLineUses.at(22) = booleanVarRow;
	// Line 23
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(23,7)
	booleanVarRow.at(8) = true; // Uses(23,8)
	bitMapLineUses.at(23) = booleanVarRow;
	// Line 24
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(8) = true; // Uses(24,8)
	bitMapLineUses.at(24) = booleanVarRow;
	// Line 25
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(25,7)
	booleanVarRow.at(8) = true; // Uses(25,8)
	bitMapLineUses.at(25) = booleanVarRow;
	// Line 26
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(26,7)
	booleanVarRow.at(8) = true; // Uses(26,8)
	bitMapLineUses.at(26) = booleanVarRow;
	// Line 27
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(8) = true; // Uses(27,8)
	bitMapLineUses.at(27) = booleanVarRow;
	// Line 28
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(28,7)
	booleanVarRow.at(8) = true; // Uses(28,8)
	bitMapLineUses.at(28) = booleanVarRow;
	// Line 29
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(8) = true; // Uses(29,8)
	bitMapLineUses.at(29) = booleanVarRow;
	// Line 30
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(8) = true; // Uses(30,8)
	bitMapLineUses.at(30) = booleanVarRow;
	// Line 31
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(31,7)
	booleanVarRow.at(8) = true; // Uses(31,8)
	bitMapLineUses.at(31) = booleanVarRow;
	// Line 32
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(8) = true; // Uses(32,8)
	bitMapLineUses.at(32) = booleanVarRow;

	pkb.setLineUsesBitMap(bitMapLineUses);

	// Set the PROCMODIFIES bit map
	// Proc 1
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Modifies(1,1)
	booleanVarRow.at(2) = true; // Modifies(1,2)
	booleanVarRow.at(3) = true; // Modifies(1,3)
	booleanVarRow.at(4) = true; // Modifies(1,4)
	booleanVarRow.at(5) = true; // Modifies(1,5)
	booleanVarRow.at(7) = true; // Modifies(1,7)
	bitMapProcModifies.at(1) = booleanVarRow;
	// Proc 2
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(4) = true; // Modifies(2,4)
	booleanVarRow.at(5) = true; // Modifies(2,5)
	booleanVarRow.at(7) = true; // Modifies(2,7)
	bitMapProcModifies.at(2) = booleanVarRow;
	// Proc 3
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(3,7)
	bitMapProcModifies.at(3) = booleanVarRow;
	// Proc 4
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Modifies(4,7)
	bitMapProcModifies.at(4) = booleanVarRow;

	pkb.setProcModifiesBitMap(bitMapProcModifies);

	// Set the PROCUSES bit map
	// Proc 1
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(1) = true; // Uses(1,1)
	booleanVarRow.at(2) = true; // Uses(1,2)
	booleanVarRow.at(5) = true; // Uses(1,5)
	booleanVarRow.at(6) = true; // Uses(1,6)
	booleanVarRow.at(7) = true; // Uses(1,7)
	booleanVarRow.at(8) = true; // Uses(1,8)
	bitMapProcUses.at(1) = booleanVarRow;
	// Proc 2
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(5) = true; // Uses(2,5)
	booleanVarRow.at(6) = true; // Uses(2,6)
	booleanVarRow.at(7) = true; // Uses(2,7)
	booleanVarRow.at(8) = true; // Uses(2,8)
	bitMapProcUses.at(2) = booleanVarRow;
	// Proc 3
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(3,7)
	booleanVarRow.at(8) = true; // Uses(3,8)
	bitMapProcUses.at(3) = booleanVarRow;
	// Proc 4
	booleanVarRow = std::vector<bool>(numVars + 1, false);
	booleanVarRow.at(7) = true; // Uses(2,7)
	booleanVarRow.at(8) = true; // Uses(2,8)
	bitMapProcUses.at(4) = booleanVarRow;

	pkb.setProcUsesBitMap(bitMapProcUses);

	/*
	
	container stmt:
	- while - 3, 6, 9, 10, 16, 20, 23, 25, 28, 31
	- if - 18, 26
	
	CommonIfMatrix 
	---3, 6, 9, 10, 16, 18, 20, 23, 25, 26, 28, 31---
	3--0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0---
	6--0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0---
	9--0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0---
	10-0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0---
	16-0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0---
	18-0, 0, 0,  0,  0, 18, 18, 18,  0,  0,  0,  0---
	20-0, 0, 0,  0,  0, 18, 18, 18,  0,  0,  0,  0---
	23-0, 0, 0,  0,  0, 18, 18, 18,  0,  0,  0,  0---
	25-0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0---
	26-0, 0, 0,  0,  0,  0,  0,  0,  0, 26, 26, 26---
	28-0, 0, 0,  0,  0,  0,  0,  0,  0, 26, 26, 26---
	31-0, 0, 0,  0,  0,  0,  0,  0,  0, 26, 26, 26---

	CommonWhileMatrix 
	---3, 6, 9, 10, 16, 18, 20, 23, 25, 26, 28, 31---
	3--3, 3, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0---
	6--3, 3, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0---
	9--0, 0, 9,  9,  0,  0,  0,  0,  0,  0,  0,  0---
	10-0, 0, 9,  9,  0,  0,  0,  0,  0,  0,  0,  0---
	16-0, 0, 0,  0, 16,  0,  0,  0,  0,  0,  0,  0---
	18-0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0---
	20-0, 0, 0,  0,  0,  0, 20,  0,  0,  0,  0,  0---
	23-0, 0, 0,  0,  0,  0,  0, 23,  0,  0,  0,  0---
	25-0, 0, 0,  0,  0,  0,  0,  0, 25, 25, 25, 25---
	26-0, 0, 0,  0,  0,  0,  0,  0, 25, 25, 25, 25---
	28-0, 0, 0,  0,  0,  0,  0,  0, 25, 25, 25, 25---
	31-0, 0, 0,  0,  0,  0,  0,  0, 25, 25, 25, 25---

	*/


	// Set Common Parent Matrix
	int numContainer = 12;
	int containerArray[] = {3, 6, 9, 10, 16, 18, 20, 23, 25, 26, 28, 31};
	int ifMatrixArray[][MAX_CONTAINER] = {
		{0}, 
		{0}, 
		{0}, 
		{0}, 
		{0}, 
		{0, 0, 0,  0,  0, 18, 18, 18,  0,  0,  0,  0}, 
		{0, 0, 0,  0,  0, 18, 18, 18,  0,  0,  0,  0}, 
		{0, 0, 0,  0,  0, 18, 18, 18,  0,  0,  0,  0}, 
		{0}, 
		{0, 0, 0,  0,  0,  0,  0,  0,  0, 26, 26, 26}, 
		{0, 0, 0,  0,  0,  0,  0,  0,  0, 26, 26, 26}, 
		{0, 0, 0,  0,  0,  0,  0,  0,  0, 26, 26, 26}, 
		};
	int whileMatrixArray[][MAX_CONTAINER] = {
		{3, 3},
		{3, 6},
		{0, 0, 9,  9},
		{0, 0, 9,  10},
		{0, 0, 0,  0, 16},
		{0},
		{0, 0, 0,  0,  0,  0, 20,  0,  0,  0,  0,  0},
		{0, 0, 0,  0,  0,  0,  0, 23,  0,  0,  0,  0},
		{0, 0, 0,  0,  0,  0,  0,  0, 25, 25, 25, 25},
		{0, 0, 0,  0,  0,  0,  0,  0, 25, 25, 25, 25},
		{0, 0, 0,  0,  0,  0,  0,  0, 25, 25, 28, 25},
		{0, 0, 0,  0,  0,  0,  0,  0, 25, 25, 25, 31},
	};

//	pkb.setCommon(Type::Entity::IF_LINE_ENTITY, prepareCommMatrixFromArray(ifMatrixArray, containerArray, numContainer));
//	pkb.setCommon(Type::Entity::WHILE_LINE_ENTITY, prepareCommMatrixFromArray(whileMatrixArray, containerArray, numContainer));
	DesignExtractor* de = new DesignExtractor(&pkb);
	de->updateEarliestCommonParent();std::cout<<"I AM HERE\n";
//	cout << "hello!!!!" << endl;
//	printParentMatrix(prepareCommMatrixFromArray(ifMatrixArray, containerArray, numContainer));
// printParentMatrix(prepareCommMatrixFromArray(whileMatrixArray, containerArray, numContainer));



	// Procedure MyProc {
	//1.	x = 2;
	//2.	y = x;
	//3.	while x {
	//4.		x = x - 1;
	//5.		y = y + x;
	//6.		while y {
	//7.			z = y - 1;
	//			}
	//		}
	//8.	y = 5;
	//9.	while x {
	//10.		while y {
	//11.			call YourProc;
	//			}
	//		}
	// }
	//
	// Procedure YourProc {
	//12.	a = 9;
	//13.	b = b + c;
	//14.	call YourOtherProc;
	// }
	//
	// Procedure YourOtherProc {
	//15.	d = d + 15;
	//16.	while d {
	//17.		d = e;
	//		}
	// }
	//
	// Procedure IfStmtProc {
	//18.	if d then {
	//19.		d = e;
	//20.		while d {
	//21.			d = e - 1 * 2;
	//			}
	//		} else {
	//22.		d = e;
	//23.		while d {
	//24.			d = e - 1 * 2;
	//			}
	//		}
	//25.	while d {
	//26.		if d then {
	//27.			d = e;
	//28.			while d {
	//29.				d = e - 1 * 2;
	//				}
	//			} else {
	//30.			d = e;
	//31.			while d {
	//32.				d = e - 1 * 2;
	//				}
	//			}
	//		}
	//	}

	return pkb;
}

void QueryEvaluatorWithPKBTest::testEvaluateFollows() {
	// Currently assumes the following SIMPLE source code:
	// Procedure MyProc {
	//1.	x = y;
	//2.	y = z;
	//3.	a = b;
	//4.	b = c;
	// }
	PKB pkb;
	//pkb.insertLineEntity(1, 1, 1, ASSIGN);
	//pkb.insertLineEntity(2, 1, 2, ASSIGN);
	//pkb.insertLineEntity(3, 1, 3, ASSIGN);
	//pkb.insertLineEntity(4, 1, 4, ASSIGN);
	//pkb.insertVar("x");pkb.insertVar("y");
	//pkb.insertVar("z");pkb.insertVar("a");
	//pkb.insertVar("b");pkb.insertVar("c");
	//pkb.setLineModifies(1, 1, 1, 1);
	//pkb.setLineModifies(2, 1, 2, 2);
	//pkb.setLineModifies(3, 1, 3, 4);
	//pkb.setLineModifies(4, 1, 4, 5);
	//pkb.setLineUses(1, 1, 1, 2);
	//pkb.setLineUses(2, 1, 2, 3);
	//pkb.setLineUses(3, 1, 3, 5);
	//pkb.setLineUses(4, 1, 4, 6);

	Type::Index::Proc procIndex = pkb.insertProc("MyProc");
	pkb.insertProcStartEnd(procIndex, 1, 4);
	pkb.insertLineEntity(1, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(2, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(3, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(4, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertVar("x");pkb.insertVar("y");
	pkb.insertVar("z");pkb.insertVar("a");
	pkb.insertVar("b");pkb.insertVar("c");
	pkb.setLineModifies(1,Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::ASSIGNMENT_LINE_ENTITY, 4);
	pkb.setLineModifies(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.setLineUses(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 3);
	pkb.setLineUses(3, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.setLineUses(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 6);
	pkb.setFollows(1, 2);
	pkb.setFollows(2, 3);
	pkb.setFollows(3, 4);
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;

	// SIMPLE CASE
	// Make a query table from: "Stmt s; Select s"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("s", NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(4, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM HAS TWO UNDERSCORE ARGUMENTS
	// Make a query table from: "Assign a; Stmt s; Select a such that Follows(_, _)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("a", NONE);
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "_", SYNONYM_PROGLINE, "_", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(4, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM DOES NOT MATCH ANY ARGUMENT
	// Make a query table from: "Assign a; Stmt s; Select a such that Follows(1, s)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "1", INTEGER, "s", SYNONYM_STMT);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(4, (int)results.size());

	// Make a query table from: "Assign a; Select a such that Follows(1, 3)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "1", INTEGER, "3", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
	
	// CASE IN WHICH THE QUERY SYNONYM MATCHES THE LEFT ARGUMENT
	// Make a query table from: "Assign a; Select a such that Follows(a, 2)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "a", SYNONYM_ASSIGN, "2", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());
	CPPUNIT_ASSERT_EQUAL(std::string("1"), results.at(0));

	// Make a query table from: "Assign a; Select a such that Follows(a, 1)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "a", SYNONYM_ASSIGN, "1", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES THE RIGHT ARGUMENT
	// Make a query table from: "Assign a; Stmt s; Select a such that Follows(s, a)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "s", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "Assign a; Select a such that Follows(4, a)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "4", INTEGER, "a", SYNONYM_ASSIGN);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES BOTH ARGUMENTS
	// Make a query table from: "Assign a; Select a such that Follows(a, a)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "a", SYNONYM_ASSIGN, "a", SYNONYM_ASSIGN);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
}

void QueryEvaluatorWithPKBTest::testEvaluateFollowsStar() {
	// Currently assumes the following SIMPLE source code:
	// Procedure MyProc {
	//1.	x = y;
	//2.	y = z;
	//3.	a = b;
	//4.	b = c;
	// }
	PKB pkb;
	//pkb.insertLineEntity(1, 1, 1, ASSIGN);
	//pkb.insertLineEntity(2, 1, 2, ASSIGN);
	//pkb.insertLineEntity(3, 1, 3, ASSIGN);
	//pkb.insertLineEntity(4, 1, 4, ASSIGN);
	//pkb.insertVar("x");pkb.insertVar("y");
	//pkb.insertVar("z");pkb.insertVar("a");
	//pkb.insertVar("b");pkb.insertVar("c");
	//pkb.setLineModifies(1, 1, 1, 1);
	//pkb.setLineModifies(2, 1, 2, 2);
	//pkb.setLineModifies(3, 1, 3, 4);
	//pkb.setLineModifies(4, 1, 4, 5);
	//pkb.setLineUses(1, 1, 1, 2);
	//pkb.setLineUses(2, 1, 2, 3);
	//pkb.setLineUses(3, 1, 3, 5);
	//pkb.setLineUses(4, 1, 4, 6);

	Type::Index::Proc procIndex = pkb.insertProc("MyProc");
	pkb.insertProcStartEnd(procIndex, 1, 4);
	pkb.insertLineEntity(1, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(2, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(3, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(4, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertVar("x");pkb.insertVar("y");
	pkb.insertVar("z");pkb.insertVar("a");
	pkb.insertVar("b");pkb.insertVar("c");
	pkb.setLineModifies(1,Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::ASSIGNMENT_LINE_ENTITY, 4);
	pkb.setLineModifies(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.setLineUses(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 3);
	pkb.setLineUses(3, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.setLineUses(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 6);
	pkb.setFollows(1, 2);
	pkb.setFollows(2, 3);
	pkb.setFollows(3, 4);
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;

	// CASE IN WHICH THE QUERY SYNONYM HAS TWO UNDERSCORE ARGUMENTS
	// Make a query table from: "Assign a; Stmt s; Select a such that Follows*(_, _)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS_STAR, "_", SYNONYM_PROGLINE, "_", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(4, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES NONE OF THE ARGUMENTS
	// Make a query table from: "Assign a; Stmt s; Select a such that Follows*(s, 2)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS_STAR, "s", SYNONYM_STMT, "2", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(4, (int)results.size());

	// Make a query table from: "Assign a; Stmt s; Select a such that Follows*(s, 1)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS_STAR, "s", SYNONYM_ASSIGN, "1", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES THE LEFT ARGUMENT
	// Make a query table from: "Assign a; Select a such that Follows*(a, 3)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS_STAR, "a", SYNONYM_ASSIGN, "3", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "Assign a; Select a such that Follows*(a, 1)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS_STAR, "a", SYNONYM_ASSIGN, "1", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES THE RIGHT ARGUMENT
	// Make a query table from: "Assign a; Select a such that Follows*(1, a)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS_STAR, "1", INTEGER, "a", SYNONYM_ASSIGN);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "Assign a; Select a such that Follows*(4, a)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS_STAR, "4", INTEGER, "a", SYNONYM_ASSIGN);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES BOTH ARGUMENTS
	// Make a query table from: "Assign a; Select a such that Follows*(a, a)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS_STAR, "a", SYNONYM_ASSIGN, "a", SYNONYM_ASSIGN);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
}

void QueryEvaluatorWithPKBTest::testEvaluateParent() {
	// Currently assumes the following SIMPLE source code:
	// Procedure MyProc {
	//1.	x = 2;
	//2.	y = x;
	//3.	while x {
	//4.		x = x - 1;
	//5.		y = y + x;
	//6.		while y {
	//7.			z = y - 1;
	//			}
	//		}
	//8.	y = 5;
	// }
	PKB pkb;
	//pkb.insertLineEntity(1, 1, 1, ASSIGN);
	//pkb.insertLineEntity(2, 1, 2, ASSIGN);
	//pkb.insertLineEntity(3, 1, 3, WHILE);
	//pkb.insertLineEntity(4, 1, 4, ASSIGN);
	//pkb.insertLineEntity(5, 1, 5, ASSIGN);
	//pkb.insertLineEntity(6, 1, 6, WHILE);
	//pkb.insertLineEntity(7, 1, 7, ASSIGN);
	//pkb.insertLineEntity(8, 1, 8, ASSIGN);
	//pkb.insertVar("x");
	//pkb.insertVar("y");
	//pkb.insertVar("z");
	//pkb.insertConstant(1, 1, 1, 2);
	//pkb.insertConstant(4, 1, 4, 1);
	//pkb.insertConstant(7, 1, 7, 1);
	//pkb.insertConstant(8, 1, 8, 5);
	//pkb.setLineModifies(1, 1, 1, 1);
	//pkb.setLineModifies(2, 1, 2, 2);
	//pkb.setLineModifies(3, 1, 3, 1);
	//pkb.setLineModifies(3, 1, 3, 2);
	//pkb.setLineModifies(3, 1, 3, 3);
	//pkb.setLineModifies(4, 1, 4, 1);
	//pkb.setLineModifies(5, 1, 5, 2);
	//pkb.setLineModifies(6, 1, 6, 3);
	//pkb.setLineModifies(7, 1, 7, 3);
	//pkb.setLineModifies(8, 1, 8, 2);
	//pkb.setLineUses(2, 1, 2, 1);
	//pkb.setLineUses(3, 1, 3, 1);
	//pkb.setLineUses(4, 1, 4, 1);
	//pkb.setLineUses(5, 1, 5, 1);
	//pkb.setLineUses(5, 1, 5, 2);
	//pkb.setLineUses(6, 1, 6, 2);
	//pkb.setLineUses(7, 1, 7, 2);

	Type::Index::Proc procIndex = pkb.insertProc("MyProc");
	pkb.insertProcStartEnd(procIndex, 1, 4);
	pkb.insertLineEntity(1, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(2, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(3, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(4, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(5, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(6, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(7, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(8, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertVar("x");
	pkb.insertVar("y");
	pkb.insertVar("z");
	pkb.insertConstant(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.insertConstant(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(8, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.setLineModifies(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 3);
	pkb.setLineModifies(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(6, Type::Entity::WHILE_LINE_ENTITY, 3);
	pkb.setLineModifies(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 3);
	pkb.setLineModifies(8, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(3, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineUses(4, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(6, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineUses(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setFollows(1, 2);
	pkb.setFollows(2, 3);
	pkb.setFollows(3, 8);
	pkb.setFollows(4, 5);
	pkb.setFollows(5, 6);
	pkb.setParent(3, 4);
	pkb.setParent(3, 5);
	pkb.setParent(3, 6);
	pkb.setParent(6, 7);
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;
	
	// TO ENSURE THAT PKB ALLOWS CONSTANT RETRIEVAL
	// constant c; Select c
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(CONSTANT, "c");
	qTable.mResultTable.addSynonym("c");
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// TO ENSURE THAT PKB ALLOWS PROG_LINE RETRIEVAL
	// prog_line p; Select p
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(8, (int)results.size());

	// stmt s; Select s such that Parent(s,4)
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("s");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT, "s", SYNONYM_STMT, "4", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM HAS TWO UNDERSCORE ARGUMENTS
	// Make a query table from: "Stmt s; Select s such that Parent(_, _)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("s");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT, "_", SYNONYM_PROGLINE, "_", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(8, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES NONE OF THE ARGUMENTS
	// Make a query table from: "assign a; while w; Select w such that Parent(w, 4)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mResultTable.addSynonym("w");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT, "w", SYNONYM_WHILE, "4", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "assign a; stmt s; Select a such that Parent(s, 8)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(ASSIGN, "s");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT, "s", SYNONYM_STMT, "8", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES THE LEFT ARGUMENT
	// Make a query table from: "while w; stmt s; Select w such that Parent(w, 4)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("w");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT, "w", SYNONYM_WHILE, "4", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES THE LEFT ARGUMENT
	// Make a query table from: "while w; Select w such that Parent(w, 4)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mResultTable.addSynonym("w");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT, "w", SYNONYM_WHILE, "8", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES THE RIGHT ARGUMENT
	// Make a query table from: "while w; assign a; Select a such that Parent(w, a)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT, "w", SYNONYM_WHILE, "a", SYNONYM_ASSIGN);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "while w; Select w such that Parent(1, w)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mResultTable.addSynonym("w");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT, "1", INTEGER, "w", SYNONYM_WHILE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES BOTH ARGUMENTS
	// Make a query table from: "while w; Select w such that Parent(w, w)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mResultTable.addSynonym("w");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT, "w", SYNONYM_WHILE, "w", SYNONYM_WHILE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
}

void QueryEvaluatorWithPKBTest::testEvaluateParentStar() {
	// Currently assumes the following SIMPLE source code:
	// Procedure MyProc {
	//1.	x = 2;
	//2.	y = x;
	//3.	while x {
	//4.		x = x - 1;
	//5.		y = y + x;
	//6.		while y {
	//7.			z = y - 1;
	//			}
	//		}
	//8.	y = 5;
	// }
	PKB pkb;
	//pkb.insertLineEntity(1, 1, 1, ASSIGN);
	//pkb.insertLineEntity(2, 1, 2, ASSIGN);
	//pkb.insertLineEntity(3, 1, 3, WHILE);
	//pkb.insertLineEntity(4, 1, 4, ASSIGN);
	//pkb.insertLineEntity(5, 1, 5, ASSIGN);
	//pkb.insertLineEntity(6, 1, 6, WHILE);
	//pkb.insertLineEntity(7, 1, 7, ASSIGN);
	//pkb.insertLineEntity(8, 1, 8, ASSIGN);
	//pkb.insertVar("x");
	//pkb.insertVar("y");
	//pkb.insertVar("z");
	//pkb.insertConstant(1, 1, 1, 2);
	//pkb.insertConstant(4, 1, 4, 1);
	//pkb.insertConstant(7, 1, 7, 1);
	//pkb.insertConstant(8, 1, 8, 5);
	//pkb.setLineModifies(1, 1, 1, 1);
	//pkb.setLineModifies(2, 1, 2, 2);
	//pkb.setLineModifies(3, 1, 3, 1);
	//pkb.setLineModifies(3, 1, 3, 2);
	//pkb.setLineModifies(3, 1, 3, 3);
	//pkb.setLineModifies(4, 1, 4, 1);
	//pkb.setLineModifies(5, 1, 5, 2);
	//pkb.setLineModifies(6, 1, 6, 3);
	//pkb.setLineModifies(7, 1, 7, 3);
	//pkb.setLineModifies(8, 1, 8, 2);
	//pkb.setLineUses(2, 1, 2, 1);
	//pkb.setLineUses(3, 1, 3, 1);
	//pkb.setLineUses(4, 1, 4, 1);
	//pkb.setLineUses(5, 1, 5, 1);
	//pkb.setLineUses(5, 1, 5, 2);
	//pkb.setLineUses(6, 1, 6, 2);
	//pkb.setLineUses(7, 1, 7, 2);

	Type::Index::Proc procIndex = pkb.insertProc("MyProc");
	pkb.insertProcStartEnd(procIndex, 1, 4);
	pkb.insertLineEntity(1, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(2, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(3, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(4, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(5, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(6, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(7, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(8, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertVar("x");
	pkb.insertVar("y");
	pkb.insertVar("z");
	pkb.insertConstant(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.insertConstant(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(8, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.setLineModifies(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 3);
	pkb.setLineModifies(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(6, Type::Entity::WHILE_LINE_ENTITY, 3);
	pkb.setLineModifies(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 3);
	pkb.setLineModifies(8, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(3, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineUses(4, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(6, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineUses(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setFollows(1, 2);
	pkb.setFollows(2, 3);
	pkb.setFollows(3, 8);
	pkb.setFollows(4, 5);
	pkb.setFollows(5, 6);
	pkb.setParent(3, 4);
	pkb.setParent(3, 5);
	pkb.setParent(3, 6);
	pkb.setParent(6, 7);
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;

	// CASE IN WHICH THE QUERY SYNONYM HAS TWO UNDERSCORE ARGUMENTS
	// Make a query table from: "Assign a; Stmt s; Select a such that Parent*(_, _)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "_", SYNONYM_PROGLINE, "_", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(6, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM DOES NOT MATCH ANY ARGUMENT
	// Make a query table from: "while w; Select w such that Parent*(3, 7)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mResultTable.addSynonym("w");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "3", INTEGER, "7", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "while w; Select w such that Parent*(1,8)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mResultTable.addSynonym("w");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "1", INTEGER, "8", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES THE LEFT ARGUMENT
	// Make a query table from: "stmt s; Select s such that Parent*(s, 7)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("s");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s", SYNONYM_WHILE, "7", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "while w; Select w such that Parent*(w, 8)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mResultTable.addSynonym("w");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "w", SYNONYM_WHILE, "8", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES THE RIGHT ARGUMENT
	// Make a query table from: "while w; stmt s; Select w such that Parent*(s, w)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("w");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s", SYNONYM_STMT, "w", SYNONYM_WHILE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "while w; Select w such that Parent*(2, w)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mResultTable.addSynonym("w");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "2", INTEGER, "w", SYNONYM_WHILE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES BOTH ARGUMENTS
	// Make a query table from: "while w; Select w such that Parent*(w, w)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mResultTable.addSynonym("w");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "w", SYNONYM_WHILE, "w", SYNONYM_WHILE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
}

void QueryEvaluatorWithPKBTest::testEvaluateModifies() {
	// Currently assumes the following SIMPLE source code:
	// Procedure MyProc {
	//1.	x = 2;
	//2.	y = x;
	//3.	while x {
	//4.		x = x - 1;
	//5.		y = y + x;
	//6.		while y {
	//7.			z = y - 1;
	//			}
	//		}
	//8.	y = 5;
	// }
	PKB pkb;
	//pkb.insertLineEntity(1, 1, 1, ASSIGN);
	//pkb.insertLineEntity(2, 1, 2, ASSIGN);
	//pkb.insertLineEntity(3, 1, 3, WHILE);
	//pkb.insertLineEntity(4, 1, 4, ASSIGN);
	//pkb.insertLineEntity(5, 1, 5, ASSIGN);
	//pkb.insertLineEntity(6, 1, 6, WHILE);
	//pkb.insertLineEntity(7, 1, 7, ASSIGN);
	//pkb.insertLineEntity(8, 1, 8, ASSIGN);
	//pkb.insertVar("x");
	//pkb.insertVar("y");
	//pkb.insertVar("z");
	//pkb.insertConstant(1, 1, 1, 2);
	//pkb.insertConstant(4, 1, 4, 1);
	//pkb.insertConstant(7, 1, 7, 1);
	//pkb.insertConstant(8, 1, 8, 5);
	//pkb.setLineModifies(1, 1, 1, 1);
	//pkb.setLineModifies(2, 1, 2, 2);
	//pkb.setLineModifies(3, 1, 3, 1);
	//pkb.setLineModifies(3, 1, 3, 2);
	//pkb.setLineModifies(3, 1, 3, 3);
	//pkb.setLineModifies(4, 1, 4, 1);
	//pkb.setLineModifies(5, 1, 5, 2);
	//pkb.setLineModifies(6, 1, 6, 3);
	//pkb.setLineModifies(7, 1, 7, 3);
	//pkb.setLineModifies(8, 1, 8, 2);
	//pkb.setLineUses(2, 1, 2, 1);
	//pkb.setLineUses(3, 1, 3, 1);
	//pkb.setLineUses(4, 1, 4, 1);
	//pkb.setLineUses(5, 1, 5, 1);
	//pkb.setLineUses(5, 1, 5, 2);
	//pkb.setLineUses(6, 1, 6, 2);
	//pkb.setLineUses(7, 1, 7, 2);

	Type::Index::Proc procIndex = pkb.insertProc("MyProc");
	pkb.insertProcStartEnd(procIndex, 1, 4);
	pkb.insertLineEntity(1, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(2, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(3, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(4, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(5, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(6, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(7, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(8, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertVar("x");
	pkb.insertVar("y");
	pkb.insertVar("z");
	pkb.insertConstant(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.insertConstant(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(8, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.setLineModifies(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 3);
	pkb.setLineModifies(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(6, Type::Entity::WHILE_LINE_ENTITY, 3);
	pkb.setLineModifies(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 3);
	pkb.setLineModifies(8, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(3, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineUses(4, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(6, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineUses(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setFollows(1, 2);
	pkb.setFollows(2, 3);
	pkb.setFollows(3, 8);
	pkb.setFollows(4, 5);
	pkb.setFollows(5, 6);
	pkb.setParent(3, 4);
	pkb.setParent(3, 5);
	pkb.setParent(3, 6);
	pkb.setParent(6, 7);
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;

	// CASE IN WHICH BOTH ARGUMENTS ARE UNDERSCORE
	// Make a query table from: "variable v; Select v such that Modifies("_","_")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_LINE, "_", SYNONYM_PROGLINE, "_", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM DOES NOT MATCH ANY ARGUMENT
	// Make a query table from: "assign a; Select a such that Modifies(1,"x")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_LINE, "1", INTEGER, "x", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(6, (int)results.size());

	// Make a query table from: "assign a; stmt s; variable v; Select a such that Modifies(s,v)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_LINE, "s", SYNONYM_STMT, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(6, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES THE LEFT ARGUMENT
	// Make a query table from: "assign a; Select a such that Modifies(a,"x")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_LINE, "a", SYNONYM_ASSIGN, "x", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "prog_line p; Select p such that Modifies(p,"z")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_LINE, "p", SYNONYM_PROGLINE, "z", STRING);
	
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES THE RIGHT ARGUMENT
	// Make a query table from: "assign a; variable v; Select v such that Modifies(a,v)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_LINE, "a", SYNONYM_ASSIGN, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "while w; variable v; Select v such that Modifies(w,v)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_LINE, "w", SYNONYM_WHILE, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "prog_line p; variable v; assign a; select p such that modifies(p, v) and modifies(a, v)
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_LINE, "p", SYNONYM_PROGLINE, "v", SYNONYM_VARIABLE);
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_LINE, "a", SYNONYM_ASSIGN, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(8, (int)results.size());
}

// Tests the evaluateQuery function for MODIFIES_PROC relationship
void QueryEvaluatorWithPKBTest::testEvaluateModifiesProcedure() {
// Procedure MyProc {
//1.	x = 2;
//2.	y = x;
//3.	while x {
//4.		x = x - 1;
//5.		y = y + x;
//6.		while y {
//7.			z = y - 1;
//			}
//		}
//8.	y = 5;
//9.	while x {
//10.		while y {
//11.			call YourProc;
//			}
//		}
// }
//
// Procedure YourProc {
//12.	a = 9;
//13.	b = b + c;
//14.	call YourOtherProc;
// }
//
// Procedure YourOtherProc {
//15.	d = d + 15;
//16.	while d {
//17.		d = e;
//		}
// }
	PKB pkb = setUpPkbWithMultipleProcedures();
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;
	/**--------------------------------------------------------------------------
	 * CASES IN WHICH NO ARGUMENTS ARE SYNONYMS
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; select p such that modifies("MyProc", "y") and modifies("MyProc", "a") and modifies("MyProc", "d");
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "MyProc", STRING, "y", STRING);
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "MyProc", STRING, "a", STRING);
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "MyProc", STRING, "d", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "procedure p; select p such that modifies("YourProc", "y")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "YourProc", STRING, "y", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// Make a query table from: "procedure p; select p such that modifies("YourProc", "_")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "YourProc", STRING, "_", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	/***--------------------------------------------------------------------------
	 * CASES IN WHICH LEFT ARGUMENT IS SYNONYM, RIGHT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; select p such that modifies(p, "d")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "p", SYNONYM_PROCEDURE, "d", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "procedure p; select p such that modifies(p, "a")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "p", SYNONYM_PROCEDURE, "a", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "procedure p; select p such that modifies(p, "x") and modifies(p, "a");
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "p", SYNONYM_PROCEDURE, "x", STRING);
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "p", SYNONYM_PROCEDURE, "a", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; select p such that modifies(p, _);
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "p", SYNONYM_PROCEDURE, "_", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH RIGHT ARGUMENT IS SYNONYM, LEFT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; variable v; select v such that modifies("YourProc", v)
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "YourProc", STRING, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "procedure p; variable v; select v such that modifies("YourProc", v) and modifies("YourOtherProc, v)
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "YourProc", STRING, "v", SYNONYM_VARIABLE);
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "YourOtherProc", STRING, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH BOTH ARGUMENTS ARE SYNONYMS
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; variable v; select p such that modifies(p, v)
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "p", SYNONYM_PROCEDURE, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "procedure p; variable v; select v such that modifies(p, v) and modifies("YourOtherProc", v)
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "p", SYNONYM_PROCEDURE, "v", SYNONYM_VARIABLE);
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_PROC, "YourOtherProc", STRING, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());
}

void QueryEvaluatorWithPKBTest::testEvaluateUses() {
	// Currently assumes the following SIMPLE source code:
	// Procedure MyProc {
	//1.	x = 2;
	//2.	y = x;
	//3.	while x {
	//4.		x = x - 1;
	//5.		y = y + x;
	//6.		while y {
	//7.			z = y - 1;
	//			}
	//		}
	//8.	y = 5;
	// }
	PKB pkb;
	//pkb.insertLineEntity(1, 1, 1, ASSIGN);
	//pkb.insertLineEntity(2, 1, 2, ASSIGN);
	//pkb.insertLineEntity(3, 1, 3, WHILE);
	//pkb.insertLineEntity(4, 1, 4, ASSIGN);
	//pkb.insertLineEntity(5, 1, 5, ASSIGN);
	//pkb.insertLineEntity(6, 1, 6, WHILE);
	//pkb.insertLineEntity(7, 1, 7, ASSIGN);
	//pkb.insertLineEntity(8, 1, 8, ASSIGN);
	//pkb.insertVar("x");
	//pkb.insertVar("y");
	//pkb.insertVar("z");
	//pkb.insertConstant(1, 1, 1, 2);
	//pkb.insertConstant(4, 1, 4, 1);
	//pkb.insertConstant(7, 1, 7, 1);
	//pkb.insertConstant(8, 1, 8, 5);
	//pkb.setLineModifies(1, 1, 1, 1);
	//pkb.setLineModifies(2, 1, 2, 2);
	//pkb.setLineModifies(3, 1, 3, 1);
	//pkb.setLineModifies(3, 1, 3, 2);
	//pkb.setLineModifies(3, 1, 3, 3);
	//pkb.setLineModifies(4, 1, 4, 1);
	//pkb.setLineModifies(5, 1, 5, 2);
	//pkb.setLineModifies(6, 1, 6, 3);
	//pkb.setLineModifies(7, 1, 7, 3);
	//pkb.setLineModifies(8, 1, 8, 2);
	//pkb.setLineUses(2, 1, 2, 1);
	//pkb.setLineUses(3, 1, 3, 1);
	//pkb.setLineUses(4, 1, 4, 1);
	//pkb.setLineUses(5, 1, 5, 1);
	//pkb.setLineUses(5, 1, 5, 2);
	//pkb.setLineUses(6, 1, 6, 2);
	//pkb.setLineUses(7, 1, 7, 2);

	Type::Index::Proc procIndex = pkb.insertProc("MyProc");
	pkb.insertProcStartEnd(procIndex, 1, 4);
	pkb.insertLineEntity(1, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(2, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(3, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(4, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(5, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(6, Type::Entity::WHILE_LINE_ENTITY);
	pkb.insertLineEntity(7, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertLineEntity(8, Type::Entity::ASSIGNMENT_LINE_ENTITY);
	pkb.insertVar("x");
	pkb.insertVar("y");
	pkb.insertVar("z");
	pkb.insertConstant(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.insertConstant(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.insertConstant(8, Type::Entity::ASSIGNMENT_LINE_ENTITY, 5);
	pkb.setLineModifies(1, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineModifies(3, Type::Entity::WHILE_LINE_ENTITY, 3);
	pkb.setLineModifies(4, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineModifies(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineModifies(6, Type::Entity::WHILE_LINE_ENTITY, 3);
	pkb.setLineModifies(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 3);
	pkb.setLineModifies(8, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(2, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(3, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineUses(4, Type::Entity::WHILE_LINE_ENTITY, 1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 1);
	pkb.setLineUses(5, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setLineUses(6, Type::Entity::WHILE_LINE_ENTITY, 2);
	pkb.setLineUses(7, Type::Entity::ASSIGNMENT_LINE_ENTITY, 2);
	pkb.setFollows(1, 2);
	pkb.setFollows(2, 3);
	pkb.setFollows(3, 8);
	pkb.setFollows(4, 5);
	pkb.setFollows(5, 6);
	pkb.setParent(3, 4);
	pkb.setParent(3, 5);
	pkb.setParent(3, 6);
	pkb.setParent(6, 7);
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;

	// CASE IN WHICH BOTH ARGUMENTS ARE UNDERSCORE
	// Make a query table from: "variable v; Select v such that Uses(_,_)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "_", SYNONYM_PROGLINE, "_", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM DOES NOT MATCH ANY ARGUMENT
	// Make a query table from: "assign a; Select a such that Uses(2,"x")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "2", INTEGER, "x", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(6, (int)results.size());

	// Make a query table from: "constant c; Select c such that Uses(2,"x")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(CONSTANT, "c");
	qTable.mResultTable.addSynonym("c");
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "2", INTEGER, "x", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "assign x; Select a such that Uses(1,"x")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "x");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "1", INTEGER, "x", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES THE LEFT ARGUMENT
	// Make a query table from: "variable v; stmt s; Select s such that Uses(s,v)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("s");
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "s", SYNONYM_STMT, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(6, (int)results.size());
	
	// Make a query table from: "stmt s; Select s such that Uses(s,"z")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("s");
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "s", SYNONYM_STMT, "z", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// CASE IN WHICH THE QUERY SYNONYM MATCHES THE RIGHT ARGUMENT
	// Make a query table from: "variable v; stmt s; Select v such that Uses(s,v)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(STMT, "s");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "s", SYNONYM_STMT, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "variable v; Select v such that Uses(1,v)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "1", INTEGER, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
}

// Tests the evaluateQuery function for USES_PROC relationship
void QueryEvaluatorWithPKBTest::testEvaluateUsesProcedure() {
// Procedure MyProc {
//1.	x = 2;
//2.	y = x;
//3.	while x {
//4.		x = x - 1;
//5.		y = y + x;
//6.		while y {
//7.			z = y - 1;
//			}
//		}
//8.	y = 5;
//9.	while x {
//10.		while y {
//11.			call YourProc;
//			}
//		}
// }
//
// Procedure YourProc {
//12.	a = 9;
//13.	b = b + c;
//14.	call YourOtherProc;
// }
//
// Procedure YourOtherProc {
//15.	d = d + 15;
//16.	while d {
//17.		d = e;
//		}
// }
	PKB pkb = setUpPkbWithMultipleProcedures();
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;
	/**--------------------------------------------------------------------------
	 * CASES IN WHICH NO ARGUMENTS ARE SYNONYMS
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; select p such that uses("MyProc", "y") and uses("MyProc", "b") and uses("MyProc", "e");
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "MyProc", STRING, "y", STRING);
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "MyProc", STRING, "b", STRING);
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "MyProc", STRING, "e", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "procedure p; select p such that uses("YourProc", "y")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "YourProc", STRING, "y", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// Make a query table from: "procedure p; select p such that uses("YourProc", _)
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "YourProc", STRING, "_", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH LEFT ARGUMENT IS SYNONYM, RIGHT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; select p such that uses(p, "e")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "e", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "procedure p; select p such that uses(p, "b")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "b", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());
	
	// Make a query table from: "procedure p; select p such that uses(p, "e") and uses(p, "y")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "e", STRING);
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "y", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; select p such that uses(p, "z")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "z", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// Make a query table from: "procedure p; select p such that uses(p, _)
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "_", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH RIGHT ARGUMENT IS SYNONYM, LEFT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "variable v; select v such that uses("YourOtherProc", v) and uses("YourProc", v)
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "YourOtherProc", STRING, "v", SYNONYM_VARIABLE);
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "YourProc", STRING, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "variable v; select v such that uses("MyProc", v)
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "MyProc", STRING, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(6, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH BOTH ARGUMENTS ARE SYNONYMS
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; variable v; select p such that uses(p, v)
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "procedure p; variable v; select v such that uses(p, v) and uses("YourOtherProc", v)
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "YourOtherProc", STRING, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());
}

// Tests the evaluateQuery function for CALLS relationship
void QueryEvaluatorWithPKBTest::testEvaluateCalls() {
// Procedure MyProc {
//1.	x = 2;
//2.	y = x;
//3.	while x {
//4.		x = x - 1;
//5.		y = y + x;
//6.		while y {
//7.			z = y - 1;
//			}
//		}
//8.	y = 5;
//9.	while x {
//10.		while y {
//11.			call YourProc;
//			}
//		}
// }
//
// Procedure YourProc {
//12.	a = 9;
//13.	b = b + c;
//14.	call YourOtherProc;
// }
//
// Procedure YourOtherProc {
//15.	d = d + 15;
//16.	while d {
//17.		d = e;
//		}
// }
	PKB pkb = setUpPkbWithMultipleProcedures();
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;
	/**--------------------------------------------------------------------------
	 * CASES IN WHICH NO ARGUMENTS ARE SYNONYMS
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; select p such that calls("MyProc", "YourProc") and calls("YourProc", "YourOtherProc)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "MyProc", STRING, "YourProc", STRING);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "YourProc", STRING, "YourOtherProc", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "procedure p; select p such that calls("MyProc", "YourOtherProc")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "MyProc", STRING, "YourOtherProc", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
	
	/**--------------------------------------------------------------------------
	 * CASES IN WHICH LEFT ARGUMENT IS SYNONYM, RIGHT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; select p such that calls(p, "YourOtherProc")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "p", SYNONYM_PROCEDURE, "YourOtherProc", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; select p such that calls(p, "YourOtherProc") and calls(p, "YourProc")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "p", SYNONYM_PROCEDURE, "YourOtherProc", STRING);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "p", SYNONYM_PROCEDURE, "YourProc", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH RIGHT ARGUMENT IS SYNONYM, LEFT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; select p such that calls("MyProc", p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "MyProc", STRING, "p", SYNONYM_PROCEDURE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; select p such that calls("MyProc", p) and calls("YourProc", p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "MyProc", STRING, "p", SYNONYM_PROCEDURE);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "YourProc", STRING, "p", SYNONYM_PROCEDURE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH BOTH ARGUMENTS ARE SYNONYMS
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p, q; select p such that calls(p,q)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(PROCEDURE, "q");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "p", SYNONYM_PROCEDURE, "q", SYNONYM_PROCEDURE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "procedure p, q, r; select r such that calls(p,q) and calls(q,r)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(PROCEDURE, "q");
	qTable.mSynonymTable.addSynonym(PROCEDURE, "r");
	qTable.mResultTable.addSynonym("r");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "p", SYNONYM_PROCEDURE, "q", SYNONYM_PROCEDURE);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "q", SYNONYM_PROCEDURE, "r", SYNONYM_PROCEDURE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p, q, r; select r such that calls(p,q) and calls(q,r) and calls(p,r)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(PROCEDURE, "q");
	qTable.mSynonymTable.addSynonym(PROCEDURE, "r");
	qTable.mResultTable.addSynonym("r");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "p", SYNONYM_PROCEDURE, "q", SYNONYM_PROCEDURE);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "q", SYNONYM_PROCEDURE, "r", SYNONYM_PROCEDURE);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS, "p", SYNONYM_PROCEDURE, "r", SYNONYM_PROCEDURE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
}

// Tests the evaluateQuery function for CALLSSTAR relationship
void QueryEvaluatorWithPKBTest::testEvaluateCallsStar() {
// Procedure MyProc {
//1.	x = 2;
//2.	y = x;
//3.	while x {
//4.		x = x - 1;
//5.		y = y + x;
//6.		while y {
//7.			z = y - 1;
//			}
//		}
//8.	y = 5;
//9.	while x {
//10.		while y {
//11.			call YourProc;
//			}
//		}
// }
//
// Procedure YourProc {
//12.	a = 9;
//13.	b = b + c;
//14.	call YourOtherProc;
// }
//
// Procedure YourOtherProc {
//15.	d = d + 15;
//16.	while d {
//17.		d = e;
//		}
// }
	PKB pkb = setUpPkbWithMultipleProcedures();
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;
	/**--------------------------------------------------------------------------
	 * CASES IN WHICH NO ARGUMENTS ARE SYNONYMS
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; select p such that calls*("MyProc", "YourOtherProc") and calls*("YourProc", "YourOtherProc")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "MyProc", STRING, "YourOtherProc", STRING);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "YourProc", STRING, "YourOtherProc", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "procedure p; select p such that calls*("YourOtherProc", "MyProc")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "YourOtherProc", STRING, "MyProc", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
	
	/**--------------------------------------------------------------------------
	 * CASES IN WHICH LEFT ARGUMENT IS SYNONYM, RIGHT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; select p such that calls*(p, "YourOtherProc")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "p", SYNONYM_PROCEDURE, "YourOtherProc", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "procedure p; select p such that calls*(p, "YourOtherProc") and calls*(p, "YourProc")
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "p", SYNONYM_PROCEDURE, "YourOtherProc", STRING);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "p", SYNONYM_PROCEDURE, "YourProc", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; select p such that calls*(p, "YourOtherProc") and calls*(p, "YourProc") and calls*(p, MyProc)
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "p", SYNONYM_PROCEDURE, "YourOtherProc", STRING);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "p", SYNONYM_PROCEDURE, "YourProc", STRING);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "p", SYNONYM_PROCEDURE, "MyProc", STRING);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH RIGHT ARGUMENT IS SYNONYM, LEFT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; select p such that calls*("MyProc", p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "MyProc", STRING, "p", SYNONYM_PROCEDURE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "procedure p; select p such that calls*("MyProc", p) and calls*("YourProc", p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "MyProc", STRING, "p", SYNONYM_PROCEDURE);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "YourProc", STRING, "p", SYNONYM_PROCEDURE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; select p such that calls*("MyProc", p) and calls*("YourProc", p) and calls*("YourOtherProc", p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "MyProc", STRING, "p", SYNONYM_PROCEDURE);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "YourProc", STRING, "p", SYNONYM_PROCEDURE);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "YourOtherProc", STRING, "p", SYNONYM_PROCEDURE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH BOTH ARGUMENTS ARE SYNONYMS
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p, q; select p such that calls*(p,q)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(PROCEDURE, "q");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "p", SYNONYM_PROCEDURE, "q", SYNONYM_PROCEDURE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "procedure p, q, r; select r such that calls*(p,q) and calls*(q,r)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(PROCEDURE, "q");
	qTable.mSynonymTable.addSynonym(PROCEDURE, "r");
	qTable.mResultTable.addSynonym("r");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "p", SYNONYM_PROCEDURE, "q", SYNONYM_PROCEDURE);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "q", SYNONYM_PROCEDURE, "r", SYNONYM_PROCEDURE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p, q, r; select r such that calls*(p,q) and calls*(q,r) and calls*(p,r)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(PROCEDURE, "q");
	qTable.mSynonymTable.addSynonym(PROCEDURE, "r");
	qTable.mResultTable.addSynonym("r");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "p", SYNONYM_PROCEDURE, "q", SYNONYM_PROCEDURE);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "q", SYNONYM_PROCEDURE, "r", SYNONYM_PROCEDURE);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "p", SYNONYM_PROCEDURE, "r", SYNONYM_PROCEDURE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p, q, r; select r such that calls*(p,q) and calls*(q,r) and calls*(p,r) and calls*(r,q)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(PROCEDURE, "q");
	qTable.mSynonymTable.addSynonym(PROCEDURE, "r");
	qTable.mResultTable.addSynonym("r");
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "p", SYNONYM_PROCEDURE, "q", SYNONYM_PROCEDURE);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "q", SYNONYM_PROCEDURE, "r", SYNONYM_PROCEDURE);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "p", SYNONYM_PROCEDURE, "r", SYNONYM_PROCEDURE);
	qTable.mRelClauseTable.addRelationshipEntry(CALLS_STAR, "r", SYNONYM_PROCEDURE, "q", SYNONYM_PROCEDURE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
}

// Tests the evaluateQuery function for NEXT relationship
void QueryEvaluatorWithPKBTest::testEvaluateNext() { 
// Sets up a PKB with the following SIMPLE source code:
// Procedure MyProc {
//1.	x = 2;
//2.	y = x;
//3.	while x {
//4.		x = x - 1;
//5.		y = y + x;
//6.		while y {
//7.			z = y - 1;
//			}
//		}
//8.	y = 5;
//9.	while x {
//10.		while y {
//11.			call YourProc;
//			}
//		}
// }
//
// Procedure YourProc {
//12.	a = 9;
//13.	b = b + c;
//14.	call YourOtherProc;
// }
//
// Procedure YourOtherProc {
//15.	d = d + 15;
//16.	while d {
//17.		d = e;
//		}
// }
//
// Procedure IfStmtProc {
//18.	if d then {
//19.		d = e;
//20.		while d {
//21.			d = e - 1 * 2;
//			}
//		} else {
//22.		d = e;
//23.		while d {
//24.			d = e - 1 * 2;
//			}
//		}
//25.	while d {
//26.		if d then {
//27.			d = e;
//28.			while d {
//29.				d = e - 1 * 2;
//				}
//			} else {
//30.			d = e;
//31.			while d {
//32.				d = e - 1 * 2;
//				}
//			}
//		}
//	}
	PKB pkb = setUpPkbWithMultipleProceduresAndIfStmts();
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;
	/**--------------------------------------------------------------------------
	 * CASES IN WHICH NO ARGUMENTS ARE SYNONYMS
	 *
	 *---------------------------------------------------------------------------*/
	// Query purpose: 
	// Make a query table from: "prog_line p; select p such that next(9,10) and next(10,11) 
	//							 and next(11,10) and next(10,9)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "9", INTEGER, "10", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "10", INTEGER, "11", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "11", INTEGER, "10", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "10", INTEGER, "9", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(32, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next(9,10) and next(10,11) and next(9,8)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "9", INTEGER, "10", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "10", INTEGER, "11", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "9", INTEGER, "8", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next(9,10) and next(10,11) and next(9,12)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "9", INTEGER, "10", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "10", INTEGER, "11", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "9", INTEGER, "12", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next(9,10) and next(10,11) and next(11, 12)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "9", INTEGER, "10", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "10", INTEGER, "11", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "11", INTEGER, "12", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next(18,19) and next(18,22)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "18", INTEGER, "19", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "18", INTEGER, "22", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(32, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next(18,19) and next(18,22) and next(18,25)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "18", INTEGER, "19", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "18", INTEGER, "22", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "18", INTEGER, "25", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
	
	/**--------------------------------------------------------------------------
	 * CASES IN WHICH LEFT ARGUMENT IS SYNONYM, RIGHT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "prog_line p; select p such that next(p,9)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p", SYNONYM_PROGLINE, "9", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next(p,9) and next(p,11)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p", SYNONYM_PROGLINE, "9", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p", SYNONYM_PROGLINE, "11", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next(p,25)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p", SYNONYM_PROGLINE, "25", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(4, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next(p,25) and next(p,29)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p", SYNONYM_PROGLINE, "25", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p", SYNONYM_PROGLINE, "29", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next(p,25) and next(p,29) and next(p, 32)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p", SYNONYM_PROGLINE, "25", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p", SYNONYM_PROGLINE, "29", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p", SYNONYM_PROGLINE, "32", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH RIGHT ARGUMENT IS SYNONYM, LEFT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "prog_line p; select p such that next(28,p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "28", INTEGER, "p", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next(28,p) and next(31,p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "28", INTEGER, "p", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "31", INTEGER, "p", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next(28,p) and next(31,p) and next(23,p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "28", INTEGER, "p", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "31", INTEGER, "p", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "23", INTEGER, "p", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next(28,p) and next(31,p) and next(23,p) and next(20,p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "28", INTEGER, "p", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "31", INTEGER, "p", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "23", INTEGER, "p", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "20", INTEGER, "p", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next(28,p) and next(31,p) and next(23,p) and next(20,p) and next(18,p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "28", INTEGER, "p", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "31", INTEGER, "p", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "23", INTEGER, "p", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "20", INTEGER, "p", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "18", INTEGER, "p", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH BOTH ARGUMENTS ARE SYNONYMS
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "prog_line p1, p2; select p1 such that next(p1,p2)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p2");
	qTable.mResultTable.addSynonym("p1");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p1", SYNONYM_PROGLINE, "p2", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(31, (int)results.size());

	// Make a query table from: "prog_line p1, p2; select p1 such that next(p1,p2) and next(p2,p1)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p2");
	qTable.mResultTable.addSynonym("p1");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p1", SYNONYM_PROGLINE, "p2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p2", SYNONYM_PROGLINE, "p1", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(15, (int)results.size());

	// Make a query table from: "assign a; prog_line p2; select a such that next(a,p2)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p2");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "a", SYNONYM_ASSIGN, "p2", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(18, (int)results.size());

	// Make a query table from: "assign a; prog_line p2; select a such that next(a,p2) and next(p2,a)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p2");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "a", SYNONYM_ASSIGN, "p2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p2", SYNONYM_PROGLINE, "a", SYNONYM_ASSIGN);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(6, (int)results.size());

	// Make a query table from: "assign a; prog_line p2; if i; select a such that next(a,p2) and next(p2,a) and next(a,i)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p2");
	qTable.mSynonymTable.addSynonym(IF, "i");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "a", SYNONYM_ASSIGN, "p2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "p2", SYNONYM_PROGLINE, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT, "a", SYNONYM_ASSIGN, "i", SYNONYM_IF);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
}

// Tests the evaluateQuery function for NEXTSTAR relationship
void QueryEvaluatorWithPKBTest::testEvaluateNextStar() {
// Sets up a PKB with the following SIMPLE source code:
// Procedure MyProc {
//1.	x = 2;
//2.	y = x;
//3.	while x {
//4.		x = x - 1;
//5.		y = y + x;
//6.		while y {
//7.			z = y - 1;
//			}
//		}
//8.	y = 5;
//9.	while x {
//10.		while y {
//11.			call YourProc;
//			}
//		}
// }
//
// Procedure YourProc {
//12.	a = 9;
//13.	b = b + c;
//14.	call YourOtherProc;
// }
//
// Procedure YourOtherProc {
//15.	d = d + 15;
//16.	while d {
//17.		d = e;
//		}
// }
//
// Procedure IfStmtProc {
//18.	if d then {
//19.		d = e;
//20.		while d {
//21.			d = e - 1 * 2;
//			}
//		} else {
//22.		d = e;
//23.		while d {
//24.			d = e - 1 * 2;
//			}
//		}
//25.	while d {
//26.		if d then {
//27.			d = e;
//28.			while d {
//29.				d = e - 1 * 2;
//				}
//			} else {
//30.			d = e;
//31.			while d {
//32.				d = e - 1 * 2;
//				}
//			}
//		}
//	}
	PKB pkb = setUpPkbWithMultipleProceduresAndIfStmts();
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;
	/**--------------------------------------------------------------------------
	 * CASES IN WHICH NO ARGUMENTS ARE SYNONYMS
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "prog_line p; select p such that next*(18,25)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "18", INTEGER, "25", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(32, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next*(1,11)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "1", INTEGER, "11", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(32, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next*(27,27)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "27", INTEGER, "27", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(32, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next*(1,11) and next*(11,12)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "1", INTEGER, "11", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "11", INTEGER, "12", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH LEFT ARGUMENT IS SYNONYM, RIGHT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "prog_line p; select p such that next*(p,11)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p", SYNONYM_PROGLINE, "11", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(11, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next*(p,14)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p", SYNONYM_PROGLINE, "14", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next*(p,26)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p", SYNONYM_PROGLINE, "26", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(15, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next*(p,26) and next*(p,23)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p", SYNONYM_PROGLINE, "26", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p", SYNONYM_PROGLINE, "23", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(4, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next*(p,26) and next*(p,23) and next*(p,18)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p", SYNONYM_PROGLINE, "26", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p", SYNONYM_PROGLINE, "23", INTEGER);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p", SYNONYM_PROGLINE, "18", INTEGER);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
	
	/**--------------------------------------------------------------------------
	 * CASES IN WHICH RIGHT ARGUMENT IS SYNONYM, LEFT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "prog_line p; select p such that next*(26,p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "26", INTEGER, "p", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(8, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next*(24,p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "24", INTEGER, "p", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(10, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next*(24,p) and next*(20,p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "24", INTEGER, "p", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "20", INTEGER, "p", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(8, (int)results.size());

	// Make a query table from: "prog_line p; select p such that next*(24,p) and next*(20,p) and next*(17,p)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "24", INTEGER, "p", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "20", INTEGER, "p", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "17", INTEGER, "p", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH BOTH ARGUMENTS ARE SYNONYMS
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "prog_line p1, p2; select p1 such that next*(p1,p2)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p2");
	qTable.mResultTable.addSynonym("p1");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p1", SYNONYM_PROGLINE, "p2", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(31, (int)results.size());

	// Make a query table from: "prog_line p1, p2; select p1 such that next*(p1,p2) and next*(p2,p1)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p2");
	qTable.mResultTable.addSynonym("p1");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p1", SYNONYM_PROGLINE, "p2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p2", SYNONYM_PROGLINE, "p1", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(22, (int)results.size());

	// Make a query table from: "prog_line p1, p2; select p1 such that next*(p1,p1)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p2");
	qTable.mResultTable.addSynonym("p1");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p1", SYNONYM_PROGLINE, "p1", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(22, (int)results.size());

	// SPEED TEST
	// Make a query table from: "prog_line p1, p2; select p1 such that next*(p1,p2) and next*(p2,p1) and next*(p1,p2) and next*(p2,p1)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p2");
	qTable.mResultTable.addSynonym("p1");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p1", SYNONYM_PROGLINE, "p2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p2", SYNONYM_PROGLINE, "p1", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p1", SYNONYM_PROGLINE, "p2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p2", SYNONYM_PROGLINE, "p1", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(22, (int)results.size());

	// SPEED TEST
	// Make a query table from: "prog_line p1, p2, p3; select p1 such that next*(p1,p2) and next*(p2,p3) and next*(p3,p1)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p2");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p3");
	qTable.mResultTable.addSynonym("p1");
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p1", SYNONYM_PROGLINE, "p2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p2", SYNONYM_PROGLINE, "p3", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p3", SYNONYM_PROGLINE, "p1", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(22, (int)results.size());
}

// Currently only tests assign patterns like Pattern a("x","5") without suchthat-clauses
void QueryEvaluatorWithPKBTest::testEvaluatePatternAssign() {
	// Currently assumes the following SIMPLE source code:
	// Procedure MyProc {
	//1.	x = 2;
	//2.	y = x;
	//3.	while x {
	//4.		x = x - 1;
	//5.		y = y + x;
	//6.		while y {
	//7.			z = y - 1;
	//			}
	//		}
	//8.	y = 5;
	// }
	PKB pkb = setUpPkb();
	QueryEvaluator evaluator(&pkb);
	QueryExpressionParser *queryExpParser = new QueryExpressionParser(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;

	TreeNode *arg2 = NULL;
	TreeNode *arg3 = NULL;
	
	cout << "TESTQUERYEVALUATOR PATTERNASSIGN: " << "1" << endl;
	// EXISTING PATTERN IN WHICH THERE IS A LEFT AND THERE IS A RIGHT ARGUMENT (NO UNDERSCORE)
	// Make a query table from: "variable v; assign a; Select v Pattern a ("y", "5")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("v");
	arg2 = queryExpParser->convertExpressionToTree("5");
	arg3 = NULL;
	CPPUNIT_ASSERT(arg2 != NULL);
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a", "y", true, arg2, true, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	cout << "TESTQUERYEVALUATOR PATTERNASSIGN: " << "2" << endl;
	// NON-EXISTING PATTERN IN WHICH THERE IS A LEFT AND THERE IS A RIGHT ARGUMENT (NO UNDERSCORE)
	// Make a query table from: "variable v; assign a; Select v Pattern a ("y", "x+x")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("v");
	arg2 = queryExpParser->convertExpressionToTree("x+x");
	arg3 = NULL;
	CPPUNIT_ASSERT(arg2 != NULL);
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a", "y", true, arg2, true, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	cout << "TESTQUERYEVALUATOR PATTERNASSIGN: " << "3" << endl;
	// EXISTING PATTERN IN WHICH THERE IS ONLY LEFT ARGUMENT (UNDERSCORE RIGHT)
	// Make a query table from: "variable v; assign a; Select v Pattern a ("y", "_")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("v");
	arg2 = NULL;
	arg3 = NULL;
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a", "y", true, arg2, false, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	cout << "TESTQUERYEVALUATOR PATTERNASSIGN: " << "4" << endl;
	// NON-EXISTING PATTERN IN WHICH THERE IS ONLY LEFT ARGUMENT (UNDERSCORE RIGHT)
	// Make a query table from: "variable v; assign a; Select v Pattern a ("b", "_")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("v");
	arg2 = NULL;
	arg3 = NULL;
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a", "b", true, arg2, false, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	cout << "TESTQUERYEVALUATOR PATTERNASSIGN: " << "5" << endl;
	// EXISTING PATTERN IN WHICH THERE IS ONLY RIGHT ARGUMENT (UNDERSCORE LEFT)
	// Make a query table from: "variable v; assign a; Select v Pattern a ("_", "y-1")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("v");
	arg2 = queryExpParser->convertExpressionToTree("y-1");
	arg3 = NULL;
	CPPUNIT_ASSERT(arg2 != NULL);
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a", "_", false, arg2, true, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	cout << "TESTQUERYEVALUATOR PATTERNASSIGN: " << "6" << endl;
	// NON-EXISTING PATTERN IN WHICH THERE IS ONLY RIGHT ARGUMENT (UNDERSCORE LEFT)
	// Make a query table from: "variable v; assign a; Select v Pattern a ("_", "y")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("v");
	arg2 = queryExpParser->convertExpressionToTree("y");
	arg3 = NULL;
	CPPUNIT_ASSERT(arg2 != NULL);
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a", "_", false, arg2, true, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	cout << "TESTQUERYEVALUATOR PATTERNASSIGN: " << "7" << endl;
	// EXISTING PATTERN IN WHICH THERE IS NO ARGUMENT (UNDERSCORE LEFT AND RIGHT)
	// Make a query table from: "variable v; assign a; Select v Pattern a ("_", "_")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("v");
	arg2 = NULL;
	arg3 = NULL;
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a", "_", false, arg2, false, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());
}

// Tests the evaluateQuery function for both such that and PATTERNS!
// Tests queries which have both a suchthat-clause and a pattern-clause
void QueryEvaluatorWithPKBTest::testEvaluateSuchThatPatternAssign() {
	// Currently assumes the following SIMPLE source code:
	// Procedure MyProc {
	//1.	x = 2;
	//2.	y = x;
	//3.	while x {
	//4.		x = x - 1;
	//5.		y = y + x;
	//6.		while y {
	//7.			z = y - 1;
	//			}
	//		}
	//8.	y = 5;
	// }
	PKB pkb = setUpPkb();
	QueryEvaluator evaluator(&pkb);
	QueryExpressionParser *queryExpParser = new QueryExpressionParser(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;

	TreeNode *arg2 = NULL;
	TreeNode *arg3 = NULL;
	
	// Make a query table from: "while w; assign a; Select a such that Follows*(w,a) pattern a("y",_)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS_STAR, "w", SYNONYM_WHILE, "a", SYNONYM_ASSIGN);
	arg2 = NULL;
	arg3 = NULL;
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a", "y", true, arg2, false, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());
	CPPUNIT_ASSERT_EQUAL(std::string("8"), results.at(0));

	// Make a query table from: "assign a1, a2; Select a1 such that Follows(a1,a2) pattern a2(_,_)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a1");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a2");
	qTable.mResultTable.addSynonym("a1");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "a1", SYNONYM_ASSIGN, "a2", SYNONYM_ASSIGN);
	arg2 = NULL;
	arg3 = NULL;
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a2", "_", false, arg2, false, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());
	CPPUNIT_ASSERT_EQUAL(std::string("1"), results.at(0));
	CPPUNIT_ASSERT_EQUAL(std::string("4"), results.at(1));

	// Make a query table from: "assign a; while w; Select a such that Parent(w,a) pattern a(_,_)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT, "w", SYNONYM_WHILE, "a", SYNONYM_ASSIGN);
	arg2 = NULL;
	arg3 = NULL;
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a", "_", false, arg2, false, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());
	CPPUNIT_ASSERT_EQUAL(std::string("4"), results.at(0));
	CPPUNIT_ASSERT_EQUAL(std::string("5"), results.at(1));
	CPPUNIT_ASSERT_EQUAL(std::string("7"), results.at(2));

	// Make a query table from: "assign a; while w; Select w such that Parent*(w,a) pattern a(_,"y-1")"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("w");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "w", SYNONYM_WHILE, "a", SYNONYM_ASSIGN);
	arg2 = queryExpParser->convertExpressionToTree("y-1");
	arg3 = NULL;
	CPPUNIT_ASSERT(arg2 != NULL);
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a", "_", false, arg2, true, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "assign a; Select a such that Modifies(a,"x") pattern a("y",_)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_LINE, "a", SYNONYM_ASSIGN, "x", STRING);
	arg2 = NULL;
	arg3 = NULL;
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a", "y", true, arg2, false, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// Make a query table from: "assign a; while w; Select a such that Parent(w,a) pattern a(_,_)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(WHILE, "w");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT, "w", SYNONYM_WHILE, "a", SYNONYM_ASSIGN);
	arg2 = NULL;
	arg3 = NULL;
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a", "_", false, arg2, false, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// THE FOLLOWING IS TESTABLE ONLY WHEN PKB CAN ACCEPT PARTIAL MATCHING

	// Make a query table from: "assign a1, a2; Select a2 such that Follows(a1,a2) pattern a2(_,_"y"_)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a1");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a2");
	qTable.mResultTable.addSynonym("a2");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "a1", SYNONYM_ASSIGN, "a2", SYNONYM_ASSIGN);
	arg2 = queryExpParser->convertExpressionToTree("y");
	arg3 = NULL;
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a2", "_", false, arg2, false, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	
	// Make a query table from: "assign a; Select a such that Modifies(a, "x") pattern a(_, _"x"_)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(MODIFIES_LINE, "a", SYNONYM_ASSIGN, "x", STRING);
	arg2 = queryExpParser->convertExpressionToTree("x");
	arg3 = NULL;
	CPPUNIT_ASSERT(arg2 != NULL);
	qTable.mPatternTable.addPattern(PATTERN_ASSIGN, "a", "_", false, arg2, false, arg3, false);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());
}

// Tests the evaluateQuery function for with-clauses
void QueryEvaluatorWithPKBTest::testEvaluateWithClauses() {
// Procedure MyProc {
//1.	x = 2;
//2.	y = x;
//3.	while x {
//4.		x = x - 1;
//5.		y = y + x;
//6.		while y {
//7.			z = y - 1;
//			}
//		}
//8.	y = 5;
//9.	while x {
//10.		while y {
//11.			call YourProc;
//			}
//		}
// }
//
// Procedure YourProc {
//12.	a = 9;
//13.	b = b + c;
//14.	call YourOtherProc;
// }
//
// Procedure YourOtherProc {
//15.	d = d + 15;
//16.	while d {
//17.		d = e;
//		}
// }
	PKB pkb = setUpPkbWithMultipleProcedures();
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;
	/**--------------------------------------------------------------------------
	 * CASES IN WHICH NO ARGUMENTS ARE SYNONYMS
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; select p such that uses("MyProc", "e") with 15=15
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "MyProc", STRING, "e", STRING);
	qTable.mConstraintTable.addConstraintEntry(WITH_INTEGER, "15", INTEGER, NONE, "15", INTEGER, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "procedure p; select p such that uses("MyProc", "e") with 15=999
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "MyProc", STRING, "e", STRING);
	qTable.mConstraintTable.addConstraintEntry(WITH_INTEGER, "15", INTEGER, NONE, "999", INTEGER, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// Make a query table from: "procedure p; select p such that uses("MyProc", "e") with "Hello" = "Hello"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "MyProc", STRING, "e", STRING);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "Hello", STRING, NONE, "Hello", STRING, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(3, (int)results.size());

	// Make a query table from: "procedure p; select p such that uses("MyProc", "e") with "Hello"="World"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "MyProc", STRING, "e", STRING);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "Hello", STRING, NONE, "World", STRING, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());
	
	/**--------------------------------------------------------------------------
	 * CASES IN WHICH LEFT ARGUMENT IS SYNONYM, RIGHT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; select p with p.procName = "YourProc"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p"); 
	qTable.mResultTable.addSynonym("p");
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "p", SYNONYM_PROCEDURE, PROC_NAME, "YourProc", STRING, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; select p such that uses("MyProc", "e") with p.procName = "YourProc"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p"); 
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "MyProc", STRING, "e", STRING);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "p", SYNONYM_PROCEDURE, PROC_NAME, "YourProc", STRING, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; variable v; select p such that uses(p, v) with p.procName = "YourProc" and v.varName = "b"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "p", SYNONYM_PROCEDURE, PROC_NAME, "YourProc", STRING, NONE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "v", SYNONYM_VARIABLE, VAR_NAME, "b", STRING, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; variable v; call c; select c such that uses(p, v) with p.procName = "YourProc" and v.varName = "b" and c.procName = "YourProc""
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(CALL, "c");
	qTable.mResultTable.addSynonym("c");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "p", SYNONYM_PROCEDURE, PROC_NAME, "YourProc", STRING, NONE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "v", SYNONYM_VARIABLE, VAR_NAME, "b", STRING, NONE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "c", SYNONYM_CALL, PROC_NAME, "YourProc", STRING, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; variable v; select p such that uses(p, v) with p.procName = "YourOtherProc" and v.varName = "b"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "p", SYNONYM_PROCEDURE, PROC_NAME, "YourOtherProc", STRING, NONE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "v", SYNONYM_VARIABLE, VAR_NAME, "b", STRING, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	/**--------------------------------------------------------------------------
	 * CASES IN WHICH RIGHT ARGUMENT IS SYNONYM, LEFT IS NOT
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p; select p with "YourProc" = p.procName
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p"); 
	qTable.mResultTable.addSynonym("p");
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "YourProc", STRING, NONE, "p", SYNONYM_PROCEDURE, PROC_NAME);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; select p such that uses("MyProc", "e") with "YourProc" = p.procName
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "MyProc", STRING, "e", STRING);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "YourProc", STRING, NONE, "p", SYNONYM_PROCEDURE, PROC_NAME);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; variable v; select p such that uses(p, v) with "YourProc" = p.procName and "b" = v.varName
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "YourProc", STRING, NONE, "p", SYNONYM_PROCEDURE, PROC_NAME);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "b", STRING, NONE, "v", SYNONYM_VARIABLE, VAR_NAME);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; variable v; call c; select c such that uses(p, v) with "YourOtherProc" = p.procName and "YourOtherProc" = c.procName"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(CALL, "c");
	qTable.mResultTable.addSynonym("c");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "YourOtherProc", STRING, NONE, "p", SYNONYM_PROCEDURE, PROC_NAME);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "YourOtherProc", STRING, NONE, "c", SYNONYM_CALL, PROC_NAME);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; variable v; select p such that uses(p, v) with "YourOtherProc" = p.procName and "b" = v.varName 
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "YourOtherProc", STRING, NONE, "p", SYNONYM_PROCEDURE, PROC_NAME);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "b", STRING, NONE, "v", SYNONYM_VARIABLE, VAR_NAME);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	/**--------------------------------------------------------------------------
	 * MIXED CASES 
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "procedure p1, p2; select p1 with p1.procName = p2.procName"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p1");
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p2");
	qTable.mResultTable.addSynonym("p");
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "p1", SYNONYM_PROCEDURE, PROC_NAME, "p2", SYNONYM_PROCEDURE, PROC_NAME);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// Make a query table from: "stmt s1, s2, s3; select s1 with s1.stmt# = s2.stmt#"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s1");
	qTable.mSynonymTable.addSynonym(STMT, "s2");
	qTable.mSynonymTable.addSynonym(STMT, "s3");
	qTable.mResultTable.addSynonym("s1");
	qTable.mConstraintTable.addConstraintEntry(WITH_INTEGER, "s1", SYNONYM_STMT, STMT_INDEX, "s2", SYNONYM_STMT, STMT_INDEX);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(17, (int)results.size());

	// Make a query table from: "stmt s1, s2, s3; select s1 with s1.stmt# = s2.stmt# and
	//													s2.stmt# = 10"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s1");
	qTable.mSynonymTable.addSynonym(STMT, "s2");
	qTable.mSynonymTable.addSynonym(STMT, "s3");
	qTable.mResultTable.addSynonym("s1");
	qTable.mConstraintTable.addConstraintEntry(WITH_INTEGER, "s1", SYNONYM_STMT, STMT_INDEX, "s2", SYNONYM_STMT, STMT_INDEX);
	qTable.mConstraintTable.addConstraintEntry(WITH_INTEGER, "s2", SYNONYM_STMT, STMT_INDEX, "10", INTEGER, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "stmt s1, s2, s3; select s1 with s1.stmt# = s2.stmt# and
	//													s2.stmt# = 10 and s3.stmt# = s2.stmt#"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s1");
	qTable.mSynonymTable.addSynonym(STMT, "s2");
	qTable.mSynonymTable.addSynonym(STMT, "s3");
	qTable.mResultTable.addSynonym("s1");
	qTable.mConstraintTable.addConstraintEntry(WITH_INTEGER, "s1", SYNONYM_STMT, STMT_INDEX, "s2", SYNONYM_STMT, STMT_INDEX);
	qTable.mConstraintTable.addConstraintEntry(WITH_INTEGER, "s2", SYNONYM_STMT, STMT_INDEX, "10", INTEGER, NONE);
	qTable.mConstraintTable.addConstraintEntry(WITH_INTEGER, "s3", SYNONYM_STMT, STMT_INDEX, "s2", SYNONYM_STMT, STMT_INDEX);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "procedure p; variable v; select p such that uses(p, v) with p.procName = v.varName"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "p", SYNONYM_PROCEDURE, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "p", SYNONYM_PROCEDURE, PROC_NAME, "v", SYNONYM_VARIABLE, VAR_NAME);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(0, (int)results.size());

	// Make a query table from: "procedure p; variable v; prog_line n1, n2; constant c; 
	//							select c such that follows(n1, n2) and uses(n1, v)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "n1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "n2");
	qTable.mSynonymTable.addSynonym(CONSTANT, "c");
	qTable.mResultTable.addSynonym("c");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "n1", SYNONYM_PROGLINE, "n2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "n1", SYNONYM_PROGLINE, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(5, (int)results.size());

	// Make a query table from: "procedure p; variable v; prog_line n1, n2; constant c; 
	//							select c such that follows(n1, n2) and uses(n1, v) with n1 = c.value and v.varName = "x""
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "n1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "n2");
	qTable.mSynonymTable.addSynonym(CONSTANT, "c");
	qTable.mResultTable.addSynonym("c");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "n1", SYNONYM_PROGLINE, "n2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "n1", SYNONYM_PROGLINE, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_INTEGER, "n1", SYNONYM_PROGLINE, NONE, "c", SYNONYM_CONSTANT, VALUE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "v", SYNONYM_VARIABLE, VAR_NAME, "x", STRING, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "procedure p; variable v; prog_line n1, n2; call c; 
	//							select c such that follows(n1, n2) and uses(n1, v) with c.procName = p.procName"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "n1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "n2");
	qTable.mSynonymTable.addSynonym(CALL, "c");
	qTable.mResultTable.addSynonym("c");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "n1", SYNONYM_PROGLINE, "n2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "n1", SYNONYM_PROGLINE, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "c", SYNONYM_CALL, PROC_NAME, "p", SYNONYM_PROCEDURE, PROC_NAME);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "procedure p; variable v; prog_line n1, n2; call c; 
	//							select c such that follows(n1, n2) and uses(n1, v) with p.procName = c.procName"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "n1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "n2");
	qTable.mSynonymTable.addSynonym(CALL, "c");
	qTable.mResultTable.addSynonym("c");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "n1", SYNONYM_PROGLINE, "n2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "n1", SYNONYM_PROGLINE, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "p", SYNONYM_PROCEDURE, PROC_NAME, "c", SYNONYM_CALL, PROC_NAME);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "procedure p; variable v; prog_line n1, n2; call c; 
	//							select c such that follows(n1, n2) and uses(n1, v) with c.procName = c.procName"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "n1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "n2");
	qTable.mSynonymTable.addSynonym(CALL, "c");
	qTable.mResultTable.addSynonym("c");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "n1", SYNONYM_PROGLINE, "n2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "n1", SYNONYM_PROGLINE, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "c", SYNONYM_CALL, PROC_NAME, "c", SYNONYM_CALL, PROC_NAME);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "procedure p; variable v; prog_line n1, n2; call c1, c2; 
	//							select c such that follows(n1, n2) and uses(n1, v) with c1.procName = c2.procName with c1.procName = p.procName with c2.procName = p.procName"
	
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "n1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "n2");
	qTable.mSynonymTable.addSynonym(CALL, "c1");
	qTable.mSynonymTable.addSynonym(CALL, "c2");
	qTable.mResultTable.addSynonym("c1");
	qTable.mRelClauseTable.addRelationshipEntry(FOLLOWS, "n1", SYNONYM_PROGLINE, "n2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "n1", SYNONYM_PROGLINE, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "c1", SYNONYM_CALL, PROC_NAME, "c2", SYNONYM_CALL, PROC_NAME);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "c1", SYNONYM_CALL, PROC_NAME, "p", SYNONYM_PROCEDURE, PROC_NAME);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "c2", SYNONYM_CALL, PROC_NAME, "p", SYNONYM_PROCEDURE, PROC_NAME);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());
}

// Tests the evaluateQuery function when selecting BOOLEAN
void QueryEvaluatorWithPKBTest::testEvaluateBooleanQuery() {
// Procedure MyProc {
//1.	x = 2;
//2.	y = x;
//3.	while x {
//4.		x = x - 1;
//5.		y = y + x;
//6.		while y {
//7.			z = y - 1;
//			}
//		}
//8.	y = 5;
//9.	while x {
//10.		while y {
//11.			call YourProc;
//			}
//		}
// }
//
// Procedure YourProc {
//12.	a = 9;
//13.	b = b + c;
//14.	call YourOtherProc;
// }
//
// Procedure YourOtherProc {
//15.	d = d + 15;
//16.	while d {
//17.		d = e;
//		}
// }
	PKB pkb = setUpPkbWithMultipleProcedures();
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;
	/**--------------------------------------------------------------------------
	 * TRUE QUERY
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "select BOOLEAN such that uses("MyProc", "e") with 15=15
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "MyProc", STRING, "e", STRING);
	qTable.mConstraintTable.addConstraintEntry(WITH_INTEGER, "15", INTEGER, NONE, "15", INTEGER, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());
	CPPUNIT_ASSERT_EQUAL(QueryEvaluator::TRUE_RESULT, results.at(0));

	/**--------------------------------------------------------------------------
	 * FALSE QUERY
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "select BOOLEAN such that uses("MyProc", "e") with 15=999
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(PROCEDURE, "p");
	qTable.mRelClauseTable.addRelationshipEntry(USES_PROC, "MyProc", STRING, "e", STRING);
	qTable.mConstraintTable.addConstraintEntry(WITH_INTEGER, "15", INTEGER, NONE, "999", INTEGER, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());
	CPPUNIT_ASSERT_EQUAL(QueryEvaluator::FALSE_RESULT, results.at(0));
}

// Tests the evaluateQuery function for mixed queries that are complex
void QueryEvaluatorWithPKBTest::testEvaluateToughQuery() {
	// Sets up a PKB with the following SIMPLE source code:
// Procedure MyProc {
//1.	x = 2;
//2.	y = x;
//3.	while x {
//4.		x = x - 1;
//5.		y = y + x;
//6.		while y {
//7.			z = y - 1;
//			}
//		}
//8.	y = 5;
//9.	while x {
//10.		while y {
//11.			call YourProc;
//			}
//		}
// }
//
// Procedure YourProc {
//12.	a = 9;
//13.	b = b + c;
//14.	call YourOtherProc;
// }
//
// Procedure YourOtherProc {
//15.	d = d + 15;
//16.	while d {
//17.		d = e;
//		}
// }
//
// Procedure IfStmtProc {
//18.	if d then {
//19.		d = e;
//20.		while d {
//21.			d = e - 1 * 2;
//			}
//		} else {
//22.		d = e;
//23.		while d {
//24.			d = e - 1 * 2;
//			}
//		}
//25.	while d {
//26.		if d then {
//27.			d = e;
//28.			while d {
//29.				d = e - 1 * 2;
//				}
//			} else {
//30.			d = e;
//31.			while d {
//32.				d = e - 1 * 2;
//				}
//			}
//		}
//	}
	PKB pkb = setUpPkbWithMultipleProceduresAndIfStmts();
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;
	/**--------------------------------------------------------------------------
	 * TODO <INSERT CASE TYPE>
	 *
	 *---------------------------------------------------------------------------*/
	// Query purpose: 
	// Make a query table from: "stmt s1, s2; assign a; variable v;
	//	Select  v such that Parent*(s1,s2) such that Parent*(s1,a) 
	//	such that Parent*(s2,a) such that Uses(a,v)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s1");
	qTable.mSynonymTable.addSynonym(STMT, "s2");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "s2", SYNONYM_STMT);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s2", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "a", SYNONYM_ASSIGN, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());

	// Make a query table from: "stmt s1, s2; assign a; variable v;
	//	Select a such that Parent*(s1,s2) such that Parent*(s1,a) 
	//	such that Parent*(s2,a) such that Uses(a,v) with v.varName = "y""
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s1");
	qTable.mSynonymTable.addSynonym(STMT, "s2");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "s2", SYNONYM_STMT);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s2", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "a", SYNONYM_ASSIGN, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "v", SYNONYM_VARIABLE, VAR_NAME, "y", STRING, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "stmt s1, s2; assign a; variable v;
	//	Select s1 such that Parent*(s1,s2) such that Parent*(s1,a) 
	//	such that Parent*(s2,a) such that Uses(a,v) with v.varName = "y""
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s1");
	qTable.mSynonymTable.addSynonym(STMT, "s2");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("s1");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "s2", SYNONYM_STMT);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s2", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "a", SYNONYM_ASSIGN, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "v", SYNONYM_VARIABLE, VAR_NAME, "y", STRING, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "stmt s1, s2; assign a; variable v;
	//	Select s2 such that Parent*(s1,s2) such that Parent*(s1,a) 
	//	such that Parent*(s2,a) such that Uses(a,v) with v.varName = "y""
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s1");
	qTable.mSynonymTable.addSynonym(STMT, "s2");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("s2");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "s2", SYNONYM_STMT);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s2", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "a", SYNONYM_ASSIGN, "v", SYNONYM_VARIABLE);
	qTable.mConstraintTable.addConstraintEntry(WITH_STRING, "v", SYNONYM_VARIABLE, VAR_NAME, "y", STRING, NONE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(1, (int)results.size());

	// Make a query table from: "stmt s1, s2; assign a; variable v;
	//	Select v such that Parent*(s1,a) such that Parent*(s2,a) 
	//	such that Parent*(s1,s2) such that Uses(a,v)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s1");
	qTable.mSynonymTable.addSynonym(STMT, "s2");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s2", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "s2", SYNONYM_STMT);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "a", SYNONYM_ASSIGN, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(2, (int)results.size());
}

// Tests the evaluateQuery function tuples querying
void QueryEvaluatorWithPKBTest::testEvaluateTuples() {
// Sets up a PKB with the following SIMPLE source code:
// Procedure MyProc {
//1.	x = 2;
//2.	y = x;
//3.	while x {
//4.		x = x - 1;
//5.		y = y + x;
//6.		while y {
//7.			z = y - 1;
//			}
//		}
//8.	y = 5;
//9.	while x {
//10.		while y {
//11.			call YourProc;
//			}
//		}
// }
//
// Procedure YourProc {
//12.	a = 9;
//13.	b = b + c;
//14.	call YourOtherProc;
// }
//
// Procedure YourOtherProc {
//15.	d = d + 15;
//16.	while d {
//17.		d = e;
//		}
// }
//
// Procedure IfStmtProc {
//18.	if d then {
//19.		d = e;
//20.		while d {
//21.			d = e - 1 * 2;
//			}
//		} else {
//22.		d = e;
//23.		while d {
//24.			d = e - 1 * 2;
//			}
//		}
//25.	while d {
//26.		if d then {
//27.			d = e;
//28.			while d {
//29.				d = e - 1 * 2;
//				}
//			} else {
//30.			d = e;
//31.			while d {
//32.				d = e - 1 * 2;
//				}
//			}
//		}
//	}
	PKB pkb = setUpPkbWithMultipleProceduresAndIfStmts();
	QueryEvaluator evaluator(&pkb);
	QueryTable qTable;
	std::vector<std::string> results;
	/**--------------------------------------------------------------------------
	 * TODO <INSERT CASE TYPE>
	 *
	 *---------------------------------------------------------------------------*/
	// Make a query table from: "assign a; Select <a,a>"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mResultTable.addSynonym("a");
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(18, (int)results.size());

	// Query purpose: 
	// Make a query table from: "stmt s1, s2; assign a; variable v;
	//	Select <s2,a> such that Parent*(s1,s2) such that Parent*(s1,a) 
	//	such that Parent*(s2,a) such that Uses(a,v)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s1");
	qTable.mSynonymTable.addSynonym(STMT, "s2");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mResultTable.addSynonym("s2");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "s2", SYNONYM_STMT);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s2", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "a", SYNONYM_ASSIGN, "v", SYNONYM_VARIABLE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(9, (int)results.size());

	// Make a query table from: "stmt s1, s2; assign a; variable v; prog_line p1, p2;
	//	Select <s2,p1> such that Parent*(s1,s2) such that Parent*(s1,a) 
	//	such that Parent*(s2,a) such that Uses(a,v) and next*(p1,p2) and next*(p2,p1)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s1");
	qTable.mSynonymTable.addSynonym(STMT, "s2");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p2");
	qTable.mResultTable.addSynonym("s2");
	qTable.mResultTable.addSynonym("p1");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "s2", SYNONYM_STMT);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s2", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "a", SYNONYM_ASSIGN, "v", SYNONYM_VARIABLE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p1", SYNONYM_PROGLINE, "p2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p2", SYNONYM_PROGLINE, "p1", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(132, (int)results.size());

	// Make a query table from: "stmt s1, s2; assign a; variable v; prog_line p1, p2;
	//	Select <s2,a> such that Parent*(s1,s2) such that Parent*(s1,a) 
	//	such that Parent*(s2,a) such that Uses(a,v) and next*(p1,p2) and next*(p2,p1)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s1");
	qTable.mSynonymTable.addSynonym(STMT, "s2");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p2");
	qTable.mResultTable.addSynonym("s2");
	qTable.mResultTable.addSynonym("a");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "s2", SYNONYM_STMT);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s2", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "a", SYNONYM_ASSIGN, "v", SYNONYM_VARIABLE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p1", SYNONYM_PROGLINE, "p2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p2", SYNONYM_PROGLINE, "p1", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(9, (int)results.size());

	// Make a query table from: "stmt s1, s2; assign a; variable v; prog_line p1, p2;
	//	Select <s2,a,v> such that Parent*(s1,s2) such that Parent*(s1,a) 
	//	such that Parent*(s2,a) such that Uses(a,v) and next*(p1,p2) and next*(p2,p1)"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(STMT, "s1");
	qTable.mSynonymTable.addSynonym(STMT, "s2");
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mSynonymTable.addSynonym(VARIABLE, "v");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p1");
	qTable.mSynonymTable.addSynonym(PROG_LINE, "p2");
	qTable.mResultTable.addSynonym("s2");
	qTable.mResultTable.addSynonym("a");
	qTable.mResultTable.addSynonym("v");
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "s2", SYNONYM_STMT);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s1", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(PARENT_STAR, "s2", SYNONYM_STMT, "a", SYNONYM_ASSIGN);
	qTable.mRelClauseTable.addRelationshipEntry(USES_LINE, "a", SYNONYM_ASSIGN, "v", SYNONYM_VARIABLE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p1", SYNONYM_PROGLINE, "p2", SYNONYM_PROGLINE);
	qTable.mRelClauseTable.addRelationshipEntry(NEXT_STAR, "p2", SYNONYM_PROGLINE, "p1", SYNONYM_PROGLINE);
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(9, (int)results.size());

	// Make a query table from: "assign a; select <a,a>"
	qTable = QueryTable();
	qTable.mSynonymTable.addSynonym(ASSIGN, "a");
	qTable.mResultTable.addSynonym("a");
	qTable.mResultTable.addSynonym("a");
	// Evaluate it!
	results = evaluator.evaluateQuery(qTable);
	CPPUNIT_ASSERT_EQUAL(18, (int)results.size());
}


Type::Map::ParentMatrix QueryEvaluatorWithPKBTest::prepareCommMatrixFromArray(int a[][MAX_CONTAINER], int index[], int size) {
	Type::Map::ParentMatrix ans;
	Type::Map::ParentMap row;
	for (int i = 0; i<size; i++) {
		row = Type::Map::ParentMap();
		for (int j = 0; j<size; j++) {
			row.insert(std::pair<Type::Index::Line, Type::Index::Line> (index[j], a[i][j]));
		}
		ans.insert(std::make_pair<Type::Index::Line, Type::Map::ParentMap> (index[i], row));
	}
	return ans;
}